如何动态切换Flutter Widget类型?实现点击切换Draggable与DragTarget
问题分析与解决方案
你的核心问题是GestureDetector与Draggable的拖拽事件冲突,加上IndexedStack切换Widget时会中断手势流,导致无法正常触发Draggable的拖拽逻辑。原方案里,GestureDetector先拦截了拖拽事件,切换index后Draggable无法接收到完整的拖拽信号,而且Widget重建会直接中断当前手势。
修正方案
不需要切换Widget,直接利用Draggable的内置回调控制状态,将DragTarget作为Draggable的默认child,拖拽时切换显示内容即可:
Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Obx(() => Draggable( data: "data", // 拖拽开始时切换状态 onDragStarted: () { c.isBeingDragged.value = true; }, // 拖拽结束后恢复状态 onDragEnd: (_) { c.isBeingDragged.value = false; }, childWhenDragging: Container( width: 40, height: 40, color: Colors.white, ), feedback: Container( width: 40, height: 40, color: Colors.blue, ), // 根据状态切换显示DragTarget或拖拽状态的容器 child: c.isBeingDragged.value ? Container( width: 40, height: 40, color: Colors.amber, ) : DragTarget( onAccept: (data) { print(data); }, builder: (context, candidateData, rejectedData) => Container( width: 40, height: 40, color: Colors.grey, ), ), )), ], )
关键改进点
- 移除了GestureDetector,用Draggable自身的
onDragStarted/onDragEnd回调控制状态,避免事件冲突。 - 不再用IndexedStack切换Widget,而是动态修改Draggable的child,保持手势连续性。
- 非拖拽状态下显示DragTarget(灰色容器),可正常接受其他拖拽元素;拖拽时切换为Draggable的激活状态(琥珀色容器),同时显示蓝色反馈层。
原代码问题总结
- 事件拦截:GestureDetector的拖拽事件会优先于Draggable触发,导致Draggable无法获取完整的拖拽信号。
- Widget重建:IndexedStack切换index时会销毁旧Widget并重建新Widget,直接中断当前的拖拽手势,无法完成拖拽流程。
内容的提问来源于stack exchange,提问作者agkts
相关产品推荐
相关产品推荐

