Small dish tries to make a common small function of news app that can add and delete item TAB by sliding. Small dish tries to use Draggable + DragTarget. Today we will first learn the basic application of Draggable drag components;

Draggable

Source code analysis

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,
})
Copy the code

Draggable is a stateful StatefulWidget component. Draggable is usually used in conjunction with DragTarget and dragged to DragTarget. Child and Feedback are two mandatory attributes, representing the child widgets displayed by default and the child widgets moved during drag.

Case try

  1. Start with a basic Draggable effect and then gradually add attribute effects.
Draggable(Child: image. asset('images/icon_hzw01.jpg', width: 150.0), feedback: Image. The asset (' images/icon_hzw02. JPG, width: 150.0));Copy the code

  1. The affinity attribute is mainly used to compete with other gestures. For example, in a vertical list, if affinity is set to Axis. Horizontal, it only allows dragging and dropping in the horizontal direction and scrolling in the vertical direction.
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)]);Copy the code

3. axisLimit drag direction, horizontal or vertical, if setnullDrag in all directions; When it conflicts with other sliding gesturesaffinityCooperate with use;

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));Copy the code

4. childWhenDraggingIs the original position child during the drag processWidgetCorresponding display content;

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), Childwhenwhendragging: image.asset ('images/icon_hzw03.jpg', width: 150.0));Copy the code

5. dragAnchorIs the position of anchor points in the process of movement, divided intochild 和 pointerTwo;childIs the default childchildThe starting point isOffset.zeroThe upper left corner shall prevail;pointerIn the childchildWithin the range, the position when the gesture is clicked shall prevail;

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);Copy the code

6. maxSimultaneousDragsFor the same childchildYou can drag the number at the same time, two fingers to two directions at the same time to try small dishes;

Draggable(Affinity: Axis. Horizontal, Axis: NULL, Child: image. asset('images/icon_hzw01.jpg', width: 150.0), feedback: Asset ('images/icon_hzw02.jpg', Width: 150.0), maxSimultaneousDrags: 2);Copy the code

  1. IgnoringFeedbackSemantics when child and feedback for the same Widget, Can pass ignoringFeedbackSemantics is set to false match the Key to ensure the same Widget reduce drawing;
Draggable(Affinity: Axis. Horizontal, Axis: null, Child: image. asset('images/icon_hzw01.jpg', width: 150.0, key: _itemKey), feedback: Image. The asset (' images/icon_hzw01. JPG, width: 150.0), ignoringFeedbackSemantics: false);Copy the code
  1. OnDraggableX is a callback function during drag; OnDragStarted is the start drag callback; OnDraggableCanceled is a callback canceled when not received by a DragTarget; OnDragEnd is the callback at the end of the drag, whether or not it is received by the DragTarget; OnDragCompleted is the callback when successfully received by DragTarget;
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'));Copy the code

  1. Data is T data of any type and is mainly passed to DragTarget.
data: 'Draggable Data A !!! ',Copy the code

DragTarget

Source code analysis

const DragTarget({
    Key key,
    @required this.builder,
    this.onWillAccept,
    this.onAccept,
    this.onLeave,
})
Copy the code

DragTarget is also a StatefulWidget with a state, where the Builder constructor is a mandatory attribute used to build the Widget after receiving the Draggable.

Case try

  1. CandidateData is the list of data that can be received when onWillAccept callback is true, and candidateData is the list of data that can be received when onWillAccept callback is true. RejectedData Specifies the data to be rejected when the onWillAccept callback is false.

2. OnWillAccept is the callback when dragged to DragTarget. True will add Data to the candidateData list; False Adds Data to the rejectedData list. 3. OnAccept is used to receive Data. 4. OnLeave is the callback before leaving. And in the course of the side dish test, when onWillAccept returns true, onAccept and onLeave are critical for whether the last coordinate of gesture drag is within the range of DragTarget.

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) : 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; });Copy the code

LongPressDraggable

Source code analysis

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,
})
Copy the code

Source code analysis can be obtained, LongPressDraggable inherited from Draggable, properties and methods are basically exactly the same, just need to long click drag;


Draggable + DragTarget case attempt


Try the Draggable drag Widget and the DragTarget corresponding to the receive drag. Next, try the News class type TAB. Xiao CAI is not familiar with the Draggable underlying source code, if you have problems, please give more guidance!

Source: Little Monk A Ce