Flutter中如何阻止DragTarget因悬停丢失已放置内容?
Flutter DragTarget 内容被意外移除问题解决
问题描述
使用DragTarget和多个Draggable组件实现拖放功能,已成功将Draggable拖放至DragTarget,但当新的Draggable悬停在已有内容的DragTarget上时,已放置的内容会被移除。尝试过IgnorePointer,但未达到预期效果。
效果演示:
相关代码片段:
onWillAccept: (data) { return data == controller.options[controller .selectedAnserIndex]; // assigning data }, onAccept: (data) { controller.updateDropped( controller.isDropped); // updating a bool to fix the drag target controller.updateIndexOfBlank(index); }, onLeave: (data) { controller.updateDropped(false); // on leave making it make it false },
解决方案
核心思路是给每个DragTarget维护「已填充」状态,从拖放逻辑层面拒绝新的拖放请求,而非简单屏蔽交互:
- 添加填充状态管理
在你的controller中新增状态,记录每个DragTarget是否已被填充:
// 假设你有固定数量的DragTarget,初始化时全为未填充 List<bool> _filledTargets = List.filled(yourTargetCount, false); // 标记目标为已填充 void markTargetFilled(int index) { _filledTargets[index] = true; notifyListeners(); } // 检查目标是否已填充 bool isTargetFilled(int index) { return _filledTargets[index]; }
- 修改DragTarget回调逻辑
调整onWillAccept、onAccept、onLeave的逻辑,结合填充状态控制拖放行为:
onWillAccept: (data) { // 仅当目标未填充且数据匹配时,才接受拖放 return !controller.isTargetFilled(index) && data == controller.options[controller.selectedAnserIndex]; }, onAccept: (data) { controller.markTargetFilled(index); // 拖放成功后标记为已填充 controller.updateIndexOfBlank(index); }, onLeave: (data) { // 仅当目标未填充时,才重置状态 if (!controller.isTargetFilled(index)) { controller.updateDropped(false); } },
问题原因说明
之前的逻辑未区分DragTarget是否已填充:
- 新Draggable悬停时,只要数据匹配就会触发
onWillAccept返回true,引发界面状态更新,导致已有内容被覆盖 onLeave会无条件重置状态,进一步导致已填充的内容因状态变化而消失
内容的提问来源于stack exchange,提问作者Febin Johnson
相关产品推荐
相关产品推荐

