Flutter Sortable Drag And Drop ListView

30,581

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/ReorderableListViews 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

enter image description here

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')              

      ],
    )
Share:
30,581

Related videos on Youtube

Jared
Author by

Jared

Updated on July 09, 2022

Comments

  • Jared
    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.

    https://storage.googleapis.com/spec-host-backup/mio-design%2Fassets%2F1dtprsH4jZ2nOnjBCJeJXd7n4U-jmWyas%2F03-list-reorder.mp4

    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
    Jared over 5 years
    Your 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
    Jared over 5 years
    I 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
    Feu over 5 years
    I 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
    Feu over 5 years
    If you are using the ReorderingListSimple, maybe you could use childrenAlreadyHaveListener = true, then place the ReorderableListener manually in to the ListTile and make it disappear on Dismissible``s onRezize`! Let me know if it works!! I know that's not great, but maybe it's valid temporary solution.
  • Andrey Turkovsky
    Andrey Turkovsky about 5 years
    It 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
    Sondre Sørbye almost 5 years
    Long press to reorder
  • UglyBob
    UglyBob almost 5 years
    Just 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
    David Mulder almost 5 years
    Do 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
    CopsOnRoad almost 5 years
    @DavidMulder That's how Flutter implemented it, you can file a bug on Github mentioning the issue.
  • David Mulder
    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
    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
    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-gestur‌​es.
  • David Mulder
    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
    Manu over 3 years
    Be 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
    matteoh over 3 years
  • MSARKrish
    MSARKrish about 3 years
    @AndreyTurkovsky ReorderableListView also having builder api.flutter.dev/flutter/material/ReorderableListView/…