拖拽控件在移动端是很常见的需求,最近我们项目中也用到了,之前在iOS端实现过,很麻烦,flutter中实现起来就很方便,在此记录一下:
要将一个 Widget 变为可拖拽的,只需要将 Widget 用 LongPressDraggable 包裹起来就可以,其中 child 和 feedback 参数是必须的:
1、child 参数 表示普通状态下的视图
2、feedback 参数 表示 长按后出现的视图
3、data 参数 表示传递的数据
4、dragAnchorStrategy 参数表示 feedback 视图的展示方式:
- pointerDragAnchorStrategy 表示 feedback 视图会跟随用户手指移动而移动
- childDragAnchorStrategy 表示 feedback 视图 会直接出现在 child 视图上方
LongPressDraggable<ARTyreWidgetModel>(
data: model,
dragAnchorStrategy: pointerDragAnchorStrategy,
feedback: DraggingARTyreWidget(dragKey: draggableKey, model: model),
child: ARTyreWidget(
model: model,
highlighted: (candidateItems.isNotEmpty &&
!candidateItems.contains(model)),
),
);
这样之后,ARTyreWidget 控件就变得可以拖拽了,还需要将其他控件变为响应 drop 事件
将 Widget 用 DragTarget 包裹起来就可以了,参数 builder 必须:
1、builder 参数 构建视图
typedef DragTargetBuilder<T> = Widget Function(BuildContext context, List<T?> candidateData, List<dynamic> rejectedData);
- 其中 candidateData 表示 用户当前正在拖拽的视图的数据中会被当前控件接受的数据,
- rejectedData 表示 用户当前正在拖拽的视图的数据中不被当前控件接受的数据
能否被当前控件接受通过范型和参数 onWillAccept 来决定
const DragTarget({
Key? key,
required this.builder,
this.onWillAccept,
this.onAccept,
this.onAcceptWithDetails,
this.onLeave,
this.onMove,
this.hitTestBehavior = HitTestBehavior.translucent,
}) : super(key: key);
以下是我的实现
DragTarget<ARTyreWidgetModel>(
builder: (context, candidateItems, rejectedItems) {
if (canMove) {
return LongPressDraggable<ARTyreWidgetModel>(
data: model,
dragAnchorStrategy: pointerDragAnchorStrategy,
feedback: DraggingARTyreWidget(dragKey: draggableKey, model: model),
child: ARTyreWidget(
model: model,
highlighted: (candidateItems.isNotEmpty &&
!candidateItems.contains(model)),
),
);
} else {
return ARTyreWidget(
model: model,
highlighted:
(candidateItems.isNotEmpty && !candidateItems.contains(model)),
);
}
},
onAccept: (value) {
if ((model?.position.isNotEmpty ?? false) &&
value.position != model?.position) {
/// MARK: 不同的位置可以交换
AssetsReceiveListItemDetailPageController? _controller =
Get.find<AssetsReceiveListItemDetailPageController>();
num? carrierId = _controller.detailModel?.carrierId;
String? fromPosition = value.position;
String? toPosition = model?.position;
logD(
"#####carrierId:$carrierId -- 原始轮位:$fromPosition -- 目标轮位:$toPosition");
if (carrierId != null &&
(fromPosition.isNotEmpty) &&
(toPosition?.isNotEmpty ?? false)) {
HttpManager.requestMoveWheel(
carrierId: carrierId,
fromPosition: fromPosition,
toPosition: toPosition!)
.then((value) {
if (value) {
_controller.requestDetailData();
}
});
}
}
},
);
效果图