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

并排DragTarget组件onLeave事件失效问题求助

解决方案

方案1:利用DragTarget内置状态(最简洁)

直接通过builder参数里的accepted列表判断当前是否有拖拽项在目标区域内,动态设置颜色,不需要手动维护额外状态:

return DragTarget<int>(
  builder: (
    BuildContext context,
    List<int?> accepted,
    List<Object?> rejected,
  ) {
    // 有被接受的拖拽项时显示红色,否则显示蓝色
    final currentColor = accepted.isNotEmpty ? Colors.red : Colors.blue;
    return Container(
      height: size.height,
      width: size.width,
      color: currentColor,
    );
  },
  onWillAcceptWithDetails: (DragTargetDetails<int> details) {
    return true;
  },
  onAcceptWithDetails: (DragTargetDetails<int> details) {
    print('dropped');
  },
);

原理:DragTarget内部会自动跟踪拖拽项的进入/离开状态,accepted列表会在拖拽项进入时填充、离开时清空,触发builder重建。这种方式完全避免了手动setState带来的状态冲突问题。


方案2:给每个DragTarget分配独立状态变量

如果需要更灵活的状态控制(比如保存拖拽前的初始颜色),可以给每个DragTarget维护独立的状态:

  1. 在父组件中用Map存储每个目标的颜色(给每个DragTarget分配唯一ID):
Map<int, Color> _targetColors = {
  0: Colors.transparent,
  1: Colors.transparent,
};
  1. 每个DragTarget绑定对应的ID,更新状态时只修改自己的颜色:
// 第一个DragTarget,ID为0
DragTarget<int>(
  builder: (context, accepted, rejected) {
    return Container(
      height: size.height,
      width: size.width,
      color: _targetColors[0],
    );
  },
  onWillAcceptWithDetails: (details) {
    setState(() {
      _targetColors[0] = Colors.red;
    });
    return true;
  },
  onLeave: (data) {
    setState(() {
      _targetColors[0] = Colors.blue;
    });
  },
  onAcceptWithDetails: (details) {
    setState(() {
      _targetColors[0] = Colors.blue;
      print('dropped on target 0');
    });
  },
),

// 第二个DragTarget,ID为1
DragTarget<int>(
  builder: (context, accepted, rejected) {
    return Container(
      height: size.height,
      width: size.width,
      color: _targetColors[1],
    );
  },
  onWillAcceptWithDetails: (details) {
    setState(() {
      _targetColors[1] = Colors.red;
    });
    return true;
  },
  onLeave: (data) {
    setState(() {
      _targetColors[1] = Colors.blue;
    });
  },
  onAcceptWithDetails: (details) {
    setState(() {
      _targetColors[1] = Colors.blue;
      print('dropped on target 1');
    });
  },
),

原理:每个DragTarget的状态独立存储,切换拖拽时两个setState修改的是不同的变量,不会互相覆盖。


问题根源

你遇到的本质问题是:两个DragTarget共享了同一个状态变量normalArea,或者在同一帧内连续触发的setState会覆盖之前的状态更新。当从A拖拽到B时,A的onLeave先把颜色设为蓝色,紧接着B的onWillAcceptWithDetails把颜色设为红色,最终状态被后面的操作覆盖,导致A的颜色没有正确更新。

内容的提问来源于stack exchange,提问作者Alexandre B.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 13:35:00