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

Flutter拖拽组句功能中DragTarget的onAccept回调未触发怎么办

问题原因

你遇到的onAccept不触发的核心诱因是拖拽操作导致页面布局偏移,同时存在多个不规范的代码写法共同加剧了问题:

  1. 你给Draggable设置了childWhenDragging: Container(),拖拽启动后原单词位置变为无高度的空容器,下方Wrap组件高度收缩,而你的Column使用MainAxisAlignment.spaceAround分配布局位置,会直接导致DragTarget区域向上偏移,你松手时指针实际已经不在DragTarget的范围内,因此不会触发onAccept。
  2. 你将DragDropBloc初始化在build方法中,每次组件重绘都会生成新的Bloc实例,既会导致状态丢失,也可能引发组件树的异常重建。
  3. 你将UI组件WordWidget作为拖拽数据传递,不符合Flutter数据驱动UI的设计规范,容易出现不可预期的类型匹配问题。
  4. Draggable的feedback组件没有包裹Material,会出现样式异常和命中检测偏差。

修复方案

1. 修复拖拽布局偏移问题

修改Draggable的childWhenDragging属性,保留原位置占位,避免Wrap高度变化:

childWhenDragging: Opacity(
  opacity: 0,
  child: WordWidget(sentence[i]),
),

同时给feedback套上Material层,消除样式异常:

feedback: Material(
  color: Colors.transparent,
  child: WordWidget(sentence[i]),
),

2. 修正Bloc初始化位置

将DragDropBloc的初始化移到State类的生命周期中,避免重复创建:

class _SentenceMakeScreenState extends State<SentenceMakeScreen> {
  // 新增Bloc成员变量
  late final DragDropBloc _dragDropBloc;
  // 原有其他成员变量不变

  @override
  void initState() {
    super.initState();
    // 初始化Bloc
    _dragDropBloc = DragDropBloc();
    _randomlyOrganizeSentence(widget.inputSentence);
    _getTextWidgets(sentence);
  }

  // 新增Bloc销毁逻辑
  @override
  void dispose() {
    _dragDropBloc.close();
    super.dispose();
  }

  // build方法中删掉原有的final _dragDropBloc = DragDropBloc();代码
  // 其余代码不变
}

3. 优化拖拽数据类型(推荐)

将拖拽数据改为纯字符串类型,避免传递UI组件带来的问题:
修改Draggable泛型与参数:

Draggable<String>(
  data: sentence[i],
  child: WordWidget(sentence[i]),
  feedback: Material(
    color: Colors.transparent,
    child: WordWidget(sentence[i]),
  ),
  childWhenDragging: Opacity(
    opacity: 0,
    child: WordWidget(sentence[i]),
  ),
)

对应修改DragTarget泛型与回调:

DragTarget<String>(
  builder: /* 原有builder逻辑不变 */,
  onWillAccept: (data) {
    print("true");
    // 新增非空校验,避免无效拖拽
    return data != null;
  },
  onAccept: (data) {
    print(data);
    _dragDropBloc.dragDropEventSink.add(
        DropEvent(WordWidget(data))
    );
    setState(() {
      this.isDragSuccessful = true;
    });
  },
)

4. 可选优化:完善WordWidget的对象匹配逻辑

为后续单词正确性校验做准备,重写WordWidget的相等判断与toString方法:

class WordWidget extends StatelessWidget {
  final String word;
  const WordWidget(this.word);

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is WordWidget &&
          runtimeType == other.runtimeType &&
          word == other.word;

  @override
  int get hashCode => word.hashCode;

  @override
  String toString() {
    return word;
  }

  // 原有build方法不变
}

内容的提问来源于stack exchange,提问作者Ratnadeep

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 09:24:00