和尚尝试做一个新闻类 app 常见的可以滑动添加和删除 item 选项卡的小功能,和尚尝试采用 Draggable + DragTarget 方式;今天先学习一下 Draggable 拖拽组件的基本应用;
const Draggable({
Key key,
@required this.child,
@required this.feedback,
this.data,
this.axis,
this.childWhenDragging,
this.feedbackOffset = Offset.zero,
this.dragAnchor = DragAnchor.child,
this.affinity,
this.maxSimultaneousDrags,
this.onDragStarted,
this.onDraggableCanceled,
this.onDragEnd,
this.onDragCompleted,
this.ignoringFeedbackSemantics = true,
})
分析源码可得,Draggable 是有状态的 StatefulWidget 组件,一般与 DragTarget 配合使用,拖拽至 DragTarget;其中 child 和 feedback 是两个必填属性,分别代表默认情况展示的子 Widget 和拖拽过程中移动时的子 Widget;
Draggable(
child: Image.asset('images/icon_hzw01.jpg', width: 150.0),
feedback: Image.asset('images/icon_hzw02.jpg', width: 150.0));
return ListView(children: <Widget>[
Icon(Icons.access_alarm, size: 100),
Icon(Icons.print, size: 100),
Icon(Icons.android, size: 100),
Draggable(
child: Icon(Icons.ac_unit, size: 150, color: Colors.blue),
feedback: Icon(Icons.ac_unit, size: 200, color: Colors.red),
affinity: Axis.horizontal),
Icon(Icons.directions_car, size: 100),
Icon(Icons.sync, size: 100),
Icon(Icons.error, size: 100),
Icon(Icons.send, size: 100),
Icon(Icons.call, size: 100)
]);
Draggable(affinity: Axis.horizontal, axis: Axis.horizontal,
child: Image.asset('images/icon_hzw01.jpg', width: 150.0),
feedback: Image.asset('images/icon_hzw02.jpg', width: 150.0));
Draggable(affinity: Axis.horizontal, axis: null,
child: Image.asset('images/icon_hzw01.jpg', width: 150.0),
feedback: Image.asset('images/icon_hzw02.jpg', width: 150.0),
childWhenDragging: Image.asset('images/icon_hzw03.jpg', width: 150.0));
Draggable(affinity: Axis.horizontal, axis: null,
child: Image.asset('images/icon_hzw01.jpg', width: 150.0),
feedback: Image.asset('images/icon_hzw02.jpg', width: 150.0),
dragAnchor: DragAnchor.pointer);
Draggable(affinity: Axis.horizontal, axis: null,
child: Image.asset('images/icon_hzw01.jpg', width: 150.0),
feedback: Image.asset('images/icon_hzw02.jpg', width: 150.0),
maxSimultaneousDrags: 2);
Draggable(affinity: Axis.horizontal, axis: null,
child: Image.asset('images/icon_hzw01.jpg', width: 150.0, key: _itemKey),
feedback: Image.asset('images/icon_hzw01.jpg', width: 150.0),
ignoringFeedbackSemantics: false);
Draggable(affinity: Axis.horizontal, axis: null,
child: Image.asset('images/icon_hzw01.jpg', width: 150.0, key: _itemKey),
feedback: Image.asset('images/icon_hzw01.jpg', width: 150.0),
childWhenDragging: Container(),
onDragCompleted: () => print('Draggable --> onDragCompleted'),
onDragEnd: (DraggableDetails details) => print('Draggable --> onDragEnd --> ${details.offset}'),
onDraggableCanceled: (Velocity velocity, Offset offset) => print('Draggable --> onDraggableCanceled --> $offset'),
onDragStarted: () => print('Draggable --> onDragStarted'));
data: 'Draggable Data A !!!',
const DragTarget({
Key key,
@required this.builder,
this.onWillAccept,
this.onAccept,
this.onLeave,
})
分析源码可得 DragTarget 同样为 StatefulWidget 带状态的 Widget,其中 builder 构造器为必填属性,用于构建接收 Draggable 后的 Widget 构建;
DragTarget<String>(builder: (BuildContext context, List<String> candidateData, List<dynamic> rejectedData) {
print('DragTarget --> builder --> $candidateData --> $rejectedData -->$_dragState');
return _dragState
? Image.asset('images/icon_hzw01.jpg', width: 150.0)
: Container(height: 150.0, width: 150.0, color: Colors.blue.withOpacity(0.4));
}, onAccept: (String data) {
print('DragTarget --> onAccept --> $data -->$_dragState');
setState(() {
_dragState = true;
});
}, onLeave: (String data) {
print('DragTarget --> onLeave --> $data');
}, onWillAccept: (String data) {
print('DragTarget --> onWillAccept --> $data');
return true;
});
const LongPressDraggable({
Key key,
@required Widget child,
@required Widget feedback,
T data,
Axis axis,
Widget childWhenDragging,
Offset feedbackOffset = Offset.zero,
DragAnchor dragAnchor = DragAnchor.child,
int maxSimultaneousDrags,
VoidCallback onDragStarted,
DraggableCanceledCallback onDraggableCanceled,
DragEndCallback onDragEnd,
VoidCallback onDragCompleted,
this.hapticFeedbackOnStart = true,
bool ignoringFeedbackSemantics = true,
})
分析源码可得,LongPressDraggable 继承自 Draggable,属性和方法基本完全一致,只是需要长按拖拽;
Draggable + DragTarget 案例尝试
和尚简答尝试了 Draggable 拖拽 Widget 以及对应接收拖拽的 DragTarget,下节尝试新闻类类型选项卡;和尚对 Draggable 底层源码还不够熟悉,如有问题请多多指导!
来源:阿策小和尚