You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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中没有触发回调的交互逻辑,比如点击、拖拽等操作,缺少触发回调的时机。

解决方法

  1. 删除State类中自定义的同名方法,避免混淆,直接使用widget.onStartDateTimeChanged来调用外部回调。
  2. 添加触发回调的交互逻辑,比如给容器添加点击手势,在用户操作时生成新的DateTime并调用回调。
  3. 确保回调调用时传入正确的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 14:17:58