Flutter:SingleChildRenderObjectWidget回调至StatefulWidget未触发问题
问题:AppointmentItem的onStartDateTimeChanged回调未触发
我编写了StatefulWidget(AppointmentItem)和SingleChildRenderObjectWidget(TimelineItem)代码,TimelineItem将onStartDateTimeChanged回调传入子组件AppointmentItem,但AppointmentItem中的onStartDateTimeChanged方法始终未被触发,求问问题原因及解决方法。
原AppointmentItem代码
class AppointmentItem extends StatefulWidget { const AppointmentItem({Key? key, required this.starttime, required this.onStartDateTimeChanged}) : super(key: key); final DateTime starttime; final void Function(DateTime)? onStartDateTimeChanged; @override State<AppointmentItem> createState() => _AppointmentItemState(); } class _AppointmentItemState extends State<AppointmentItem> { onStartDateTimeChanged() { setState(() { print("hallo CB"); }); } @override Widget build(BuildContext context) { return Container( alignment: Alignment.center, width: double.infinity, height: double.infinity, decoration: BoxDecoration( color: Colors.amberAccent, borderRadius: BorderRadius.circular(10), ), child: Column( children: [ Row( children: [ Text(widget.starttime.toString()), ], ), Text("hallo"), ], ), ); } }
原TimelineItem代码
class TimelineItem extends SingleChildRenderObjectWidget { TimelineItem({ Key? key, required this.startDateTime, required this.endDateTime, this.position = 0, this.onStartDateTimeChanged, this.onEndDateTimeChanged, this.onStartDateTimeUpdated, this.onEndDateTimeUpdated, }) : assert( startDateTime.isBefore(endDateTime), 'startDateTime must be before endDateTime: ' 'starDateTime: $startDateTime --- endDateTime: $endDateTime', ), super( key: key, child: AppointmentItem(starttime: startDateTime, onStartDateTimeChanged: onStartDateTimeChanged,), ); final DateTime startDateTime; final DateTime endDateTime; final int position; final void Function(DateTime)? onStartDateTimeChanged; final void Function(DateTime)? onEndDateTimeChanged; final void Function(DateTime)? onStartDateTimeUpdated; final void Function(DateTime)? onEndDateTimeUpdated; @override RenderObject createRenderObject(BuildContext context) { return RenderTimelineItem( startDateTime: startDateTime, endDateTime: endDateTime, position: position, onStartDateTimeUpdated: onStartDateTimeUpdated, onEndDateTimeUpdated: onEndDateTimeUpdated, onStartDateTimeChanged: onStartDateTimeChanged, onEndDateTimeChanged: onEndDateTimeChanged, ); } @override void updateRenderObject( BuildContext context, covariant RenderTimelineItem renderObject, ) { renderObject ..startDateTime = startDateTime ..endDateTime = endDateTime ..position = position ..onStartDateTimeUpdated = onStartDateTimeUpdated ..onEndDateTimeUpdated = onEndDateTimeUpdated ..onStartDateTimeChanged = onStartDateTimeChanged ..onEndDateTimeChanged = onEndDateTimeChanged; } }
问题原因
- State类中自定义的
onStartDateTimeChanged方法和widget参数传入的回调完全无关,你没有在任何地方调用外部传入的widget.onStartDateTimeChanged。 - AppointmentItem的UI中没有触发回调的交互逻辑,比如点击、拖拽等操作,缺少触发回调的时机。
解决方法
- 删除State类中自定义的同名方法,避免混淆,直接使用
widget.onStartDateTimeChanged来调用外部回调。 - 添加触发回调的交互逻辑,比如给容器添加点击手势,在用户操作时生成新的DateTime并调用回调。
- 确保回调调用时传入正确的DateTime参数,符合外部预期。
修改后的AppointmentItem代码
class AppointmentItem extends StatefulWidget { const AppointmentItem({Key? key, required this.starttime, required this.onStartDateTimeChanged}) : super(key: key); final DateTime starttime; final void Function(DateTime)? onStartDateTimeChanged; @override State<AppointmentItem> createState() => _AppointmentItemState(); } class _AppointmentItemState extends State<AppointmentItem> { @override Widget build(BuildContext context) { // 添加手势检测,点击时触发回调 return GestureDetector( onTap: () { // 生成一个新的时间(示例:当前时间加1小时) final newStartTime = widget.starttime.add(const Duration(hours: 1)); // 调用外部传入的回调 widget.onStartDateTimeChanged?.call(newStartTime); // 如果需要更新本地UI,可在这里setState setState(() { print("触发回调,新时间:$newStartTime"); }); }, child: Container( alignment: Alignment.center, width: double.infinity, height: double.infinity, decoration: BoxDecoration( color: Colors.amberAccent, borderRadius: BorderRadius.circular(10), ), child: Column( children: [ Row( children: [ Text(widget.starttime.toString()), ], ), Text("点击修改时间"), ], ), ), ); } }
额外说明:如果你的RenderTimelineItem中会主动触发onStartDateTimeChanged回调,需确保RenderObject中正确调用了这个回调,目前你的TimelineItem代码已做到传递同一个回调实例给AppointmentItem和RenderObject,这部分无需修改。
内容的提问来源于stack exchange,提问作者Lukas Fürst
相关产品推荐
相关产品推荐

