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; }); },
修正其他代码错误
BorderSize.none是错误写法,应改为BorderSide.none- 确保
setState操作的是类成员变量_dropZone(原代码里的dropZone是笔误) - 去掉
_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
相关产品推荐
相关产品推荐

