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

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维护「已填充」状态,从拖放逻辑层面拒绝新的拖放请求,而非简单屏蔽交互:

  1. 添加填充状态管理
    在你的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];
}
  1. 修改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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 09:22:38