问题
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?
回答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.
回答2:
Flutter itself provides a (Material) ReorderableListView class.
回答3:
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(() {});
},
),
);
}
回答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
回答5:
Flutter team introduced ReorderableListView widget.
ReorderableListView(
children: <Widget>[
for (var item in appState.menuButtons)
Text('data')
],
)
来源:https://stackoverflow.com/questions/53908025/flutter-sortable-drag-and-drop-listview