Flutter Sortable Drag And Drop ListView
Solution 1
Check knopp/flutter_reorderable_list. It accomplishes just that. It's really smooth and it's got no performance issues, being able to handle thousands of items.
However, it's implementation is not easy as usual flutter widgets.
If you struggle with that, I'd recommend you to use a widget I created to port flutter/ReorderableListView
s to the knopp/ReorderableList
.
This widget makes it really easy to use, however it doesn't provide the same flexibility, and as it works with a children
List
, it's not as scalable as the original.
Here's the code for ReorderableListSimple and this is the demo.
Solution 2
You can use native flutter widget, ReorderableListView
to achieve it, here is the example of doing it.
List<String> _list = ["Apple", "Ball", "Cat", "Dog", "Elephant"];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: ReorderableListView(
children: _list.map((item) => ListTile(key: Key("${item}"), title: Text("${item}"), trailing: Icon(Icons.menu),)).toList(),
onReorder: (int start, int current) {
// dragging from top to bottom
if (start < current) {
int end = current - 1;
String startItem = _list[start];
int i = 0;
int local = start;
do {
_list[local] = _list[++local];
i++;
} while (i < end - start);
_list[end] = startItem;
}
// dragging from bottom to top
else if (start > current) {
String startItem = _list[start];
for (int i = start; i > current; i--) {
_list[i] = _list[i - 1];
}
_list[current] = startItem;
}
setState(() {});
},
),
);
}
Solution 3
Flutter itself provides a (Material) ReorderableListView class.
Solution 4
I've tried flutter_reorderable_list and dragable_flutter_list but none of them worked properly - there was some unwanted artifacts during dragging. So I've tried to make own solution:
ListView.builder(
itemBuilder: (context, index) => buildRow(index),
itemCount: trackList.length,
),
Widget buildRow(int index) {
final track = trackList[index];
ListTile tile = ListTile(
title: Text('${track.getName()}'),
);
Draggable draggable = LongPressDraggable<Track>(
data: track,
axis: Axis.vertical,
maxSimultaneousDrags: 1,
child: tile,
childWhenDragging: Opacity(
opacity: 0.5,
child: tile,
),
feedback: Material(
child: ConstrainedBox(
constraints:
BoxConstraints(maxWidth: MediaQuery.of(context).size.width),
child: tile,
),
elevation: 4.0,
),
);
return DragTarget<Track>(
onWillAccept: (track) {
return trackList.indexOf(track) != index;
},
onAccept: (track) {
setState(() {
int currentIndex = trackList.indexOf(track);
trackList.remove(track);
trackList.insert(currentIndex > index ? index : index - 1, track);
});
},
builder: (BuildContext context, List<Track> candidateData,
List<dynamic> rejectedData) {
return Column(
children: <Widget>[
AnimatedSize(
duration: Duration(milliseconds: 100),
vsync: this,
child: candidateData.isEmpty
? Container()
: Opacity(
opacity: 0.0,
child: tile,
),
),
Card(
child: candidateData.isEmpty ? draggable : tile,
)
],
);
},
);
}
I guess, this is not the best solution, and I'm maybe will change it further, but for now it works quite well
Solution 5
Flutter team introduced ReorderableListView widget.
ReorderableListView(
children: <Widget>[
for (var item in appState.menuButtons)
Text('data')
],
)
Related videos on Youtube
Jared
Updated on July 09, 2022Comments
-
Jared almost 2 years
So I'm starting to learn Flutter and would like to use a material design drag and drop list just like the one seen on the material guidelines website.
All of the libraries I have tried out so far look like garbage compared to that. Is there a good library for this that I am missing or a native Flutter widget?
-
Jared over 5 yearsYour version worked great, thanks. I would like it to be a little less laggy though when reordering every tile. Don't know if it will be smoother in the release version. Also, I can't figure out how to customize / remove the vibrations when reordering.
-
Jared over 5 yearsI also just ran into the issue where when I make the list tile dismissable (flutter.io/docs/cookbook/gestures/dismissible) the handle doesn't move while the rest of it slides away as it should.
-
Feu over 5 yearsI know it's not a solution, but in my app, after some fighting, I decided to use a reordering mode. :( So in reordering mode I use the ReorderingList and there's a handle (and you can't do anything else), and when it's not reordering then the user can do all the rest.
-
Feu over 5 yearsIf you are using the
ReorderingListSimple
, maybe you could usechildrenAlreadyHaveListener = true
, then place theReorderableListener
manually in to theListTile
and make it disappear onDismissible``s
onRezize`! Let me know if it works!! I know that's not great, but maybe it's valid temporary solution. -
Andrey Turkovsky about 5 yearsIt seems that I've done a little useless work ))) Anyway, it was interesting experience. It's a pity that `ReorderableListView' doesn't use builder, but I think I'll use it for my needs. Thanks
-
Sondre Sørbye almost 5 yearsLong press to reorder
-
UglyBob almost 5 yearsJust a detail, as I understand it you should avoid empty setState calls and it seems to me as all the code in onReorder could just as well be inside the setState call?
-
David Mulder almost 5 yearsDo note, the long press to reorder is absolutely breaking the material design spec and should not be used on Android (no idea about iOS). As far as I have been able to figure out so far there is no way to provide handles which can be simply grabbed with
ReorderableListView
-
CopsOnRoad almost 5 years@DavidMulder That's how Flutter implemented it, you can file a bug on Github mentioning the issue.
-
David Mulder almost 5 years@CopsOnRoad Was going to do that, but then noticed there are 5000 open issues on the Flutter Github and realized that 1) it would be pointless to post there and 2) that I will definitely not be doing any production work with flutter 😅 . So yeah, just wanted to leave that as an aside here as it's a pretty important thing to realize and it's not that obvious from the image you included.
-
CopsOnRoad almost 5 years@DavidMulder 5000+ issues doesn't really mean they are going to be solved in "oldest to newest" pattern, you are most welcome to post any bug you see, and you should get the reply in around 24-48 hours.
-
A. Bourgoin about 4 years@DavidMulder and for future readers : Do use long press to reorder, it is absolutely part of material design. See material.io/design/interaction/gestures.html#types-of-gestures.
-
David Mulder about 4 years@A.Bourgoin That's incorrect, please check material.io/components/lists#behavior "To reorder a list item, drag it.". The "long press" is described for content blocks, not lists (e.g. an editor where a normal drag means selection) or elements with a clear drag handle.
-
Manu over 3 yearsBe aware this is currently lacking some features that are implemented in ListView. The Flutter team is aware, but they are still open to recommendations. You can follow this here: github.com/flutter/flutter/issues/66080
-
matteoh over 3 yearsYou should try pub.dev/packages/implicitly_animated_reorderable_list
-
MSARKrish about 3 years@AndreyTurkovsky ReorderableListView also having builder api.flutter.dev/flutter/material/ReorderableListView/…