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

Flutter:实现Draggable悬停DragTarget时高亮对应边框的问题

解决方案:根据拖拽位置高亮DragTarget的上下边框

核心问题是你偏移转换的方向搞反了——应该把拖拽的全局偏移转为DragTarget的本地偏移,而不是反过来。以下是修正后的实现:

关键修正:onMove 方法逻辑

在onMove中,我们需要将拖拽的全局位置转换为DragTarget组件内部的本地坐标,再对比中点判断区域:

onMove: (details) {
  final box = _key.currentContext?.findRenderObject() as RenderBox?;
  if (box == null) return;
  
  // 将拖拽的全局偏移转为DragTarget的本地偏移
  final localOffset = box.globalToLocal(details.offset);
  // 获取DragTarget的高度中点
  final midY = box.size.height / 2;
  
  setState(() {
    // 根据本地偏移的y值判断区域
    _dropZone = localOffset.y < midY ? DropZone.top : DropZone.bottom;
  });
},

修正其他代码错误

  1. BorderSize.none 是错误写法,应改为 BorderSide.none
  2. 确保setState操作的是类成员变量_dropZone(原代码里的dropZone是笔误)
  3. 去掉_dropZone的final修饰符,否则无法通过setState修改

完整修正后的代码

enum DropZone { top, bottom }

final GlobalKey _key = GlobalKey();
DropZone _dropZone = DropZone.bottom;

Widget _draggable() {
  return LongPressDraggable(
    data: "some-data",
    feedback: Container(height: 100, width: 100, color: Colors.yellow),
    child: Container(
      height: 100,
      width: 100,
      child: const Center(child: Text("Hello, World!")),
    ),
  );
}

BorderSide _borderSide(DropZone dropZone) {
  if (_dropZone == dropZone) {
    return const BorderSide(color: Colors.blue, width: 2); // 加宽边框让高亮更明显
  }
  return BorderSide.none;
}

Widget _dropTarget() {
  return DragTarget(
    key: _key,
    builder: (ctx, candidateData, rejectData) => Container(
      height: 100,
      width: 100,
      decoration: BoxDecoration(
        border: Border(
          top: _borderSide(DropZone.top),
          bottom: _borderSide(DropZone.bottom),
        ),
      ),
    ),
    onWillAcceptWithDetails: (details) {
      return true; // 允许接受拖拽数据
    },
    onMove: (details) {
      final box = _key.currentContext?.findRenderObject() as RenderBox?;
      if (box == null) return;
      
      final localOffset = box.globalToLocal(details.offset);
      final midY = box.size.height / 2;
      
      setState(() {
        _dropZone = localOffset.y < midY ? DropZone.top : DropZone.bottom;
      });
    },
  );
}

逻辑说明

  • globalToLocal将拖拽的全局位置转换为DragTarget内部的坐标,此时localOffset.y的取值范围是0到DragTarget的高度
  • 对比localOffset.y和高度中点midY,就能准确判断拖拽位置在上半区还是下半区
  • 给高亮边框增加width参数,让视觉反馈更清晰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 23:37:03