“This is the fifth day of my participation in the First Challenge 2022. For details: First Challenge 2022.”
preface
Today is the first day when I returned to work. I still can’t accept the end of the holiday. I just think it was a dream.
Get back to business,
The topic of this article is how to implement drag sort in Flutter;
Of course, flutter itself has a ReorderableListView, but there is no such thing as a ReorderableGridView if you need to do a drag and drop sort on gridViews, waterfall streams, etc.
This is where the almighty Pub. Dev comes in
Reorderable introduction
If you search for reorder in the pub, you can find reorderable with the most likes.
According to its description, it provides many types of sortable components,
One of them, ReorderableWrap, was just what I needed… Well, in part; That’s what we’re going to talk about this time: long drag sort;
How reorderable is implemented
As usual, start with the problem analysis process:
First of all, the realization of its process put forward such a few questions:
- After long press will leave a virtual shadow in place, this is how to achieve;
- When moving to another Item, how do I determine whether to insert before or after the target Item?
- After sorting, all other items move backwards or forwards. How does this effect work?
To solve these problems, first look at the basic mechanism and principles:
To understand the basic structure, come to the Build method:
Build method quick overview:
The build method finally returned, the default is actually a Wrap, namely the defaultBuildItemContainer structure, so came to wrappedChildren suspicious parts:
The wrappedChildren, however, just wraps a layer of child ????? So the core is this _wrap method, right?
But it’s kind of alarming that there’s a sort of ordering, so let me just remember:
So let’s look at the questionable _wrap method:
The _wrap method gives a quick overview
The _wrap method is quite long, but let’s look at the return part first;
Return the _wrap, _buildContainerForMainAxis method is to return a wrap, for understanding the structure, like meaningless;
_includeMovedAdjacentChildIfNeeded interesting, it is according to the _ghostDisplayIndex and _currentDisplayIndex, as well as the incoming childDisplayIndex, Make a transformation to the constructed dragTarget to determine whether disappearingPreChild needs to be added and the order of addition. After all, these parameters are for what purpose, I don’t know.
The dragTarget below is the core of the Reorderables implementation;
DragTarget is a stack, which is made up of three layers: containedDraggable. Builder; PreDragTarget (half the size of left and top) and nextDragTrget (half the size of Right and bottom)
Someone should look out, actually more than here, also appeared many times in front of the Draggable DragTarget related part of the word;
So the core technology is the combination of Draggable and DragTarget; PreDragTarget and nextDragTarget are actually dragtargets
And the above mentioned containedDraggable. Builder, in fact, the Draggable:
So the structure is pretty clear, just to summarize
The Wrap container contains several items, each of which is a Stack. In addition to the contents of the Item, a half SizeBox is placed on each side as a DragTarget.
Once the basic structure is understood, it seems that some of the questions are actually answered…
Long press the virtual shadow left by the realization of:
Draggable provides the childWhenDragging method to leave a placeholder in place while dragging;
So this placeholder to do a translucent processing, that is not virtual shadow?
After Item is dragged to the specified position, the judgment method of moving position is as follows:
As described above in the basic structure analysis, each Item actually contains two dragtargets, each half of which is equal to the other half. Drag to which DragTarget responds:
How to move animation in sequence:
Once the position is known, how to implement the inserted animation depends on the onWillAccept method, which handles the response:
The first is to calculate some parameters, do some boundary judgment, and determine that the sliding response Item is corresponding to itself, so don’t do the response, and so on:
Here’s the part that actually triggers the animation in response to the action:
Here to trigger a setState, modify _nextDisplayIndex, triggering _requestAnimationToNextIndex
Parameters of the first no matter, setState overall look again after the completion of concrete action, so look at the _requestAnimationToNextIndex method:
This sets the values of _ghostDisplayIndex and _currentDisplayIndex, and triggers two AnimationControllers
_ghostDisplayIndex _currentDisplayIndex _ghostDisplayIndex
So, like, in the build method, it’s sort by _currentDisplayIndex, right?
Then the role of setState is clear, ordering directly and inserting items already in the childWhenDragging state so that the virtual image is displayed to the target position;
The usefulness of these two AnimationControllers depends on where they are called
From the previous texture, you can see that many parts, Item display contents are wrapped in a layer, such as childWhenDragging, Child is a _makeAppearingWidget, builder method, The widget generated by _makeDisappearingWidget is added to the List.
_MakeMakeAppearingWidget and _makeDisappearingWidget wrap items in the target location and drag Item
In fact, these two controllers control the two widgets. One handles the move back animation when adding and the other handles the move forward animation when removing.
The implementation is also simple:
That’s right, SizeTranstion, which animates the size of the Item and squeezes it out…
To sum up:
After setState, the build method moves the dragged Item to the target position. At this point, the size of the Item itself is 0. As the animation plays, SizeTranstion gradually changes the size of the Item. (This method I did not think at that time, can also play ~ ~ ~)
Of course, there will be a small treatment for special cases:
When a row crossing occurs, animate the first Item of the row from small to large.
conclusion
I thought I was going to do it with overlays or something, but it didn’t have to be that complicated. It was pretty simple:
International conventions, renderings:
So here’s how to tweak this, add that folder function;