前面咱們對於 ListView
的操做講過 Flutter 滑動刪除最佳實踐,那如今咱們來了解一下 ListView
的拖拽排序。html
效果以下:api
想要達到如上效果,需使用該類,官網簡介:數組
A list whose items the user can interactively reorder by dragging.app
This class is appropriate for views with a small number of children because constructing the List requires doing work for every child that could possibly be displayed in the list view instead of just those children that are actually visible.ide
All children must have a key.函數
簡單翻譯以下:測試
用戶能夠經過拖動來從新排序的列表。ui
該類適用於少許 children 的頁面,由於構造列表須要爲每個 children 執行操做,而不僅是可見的 children。this
全部的 children 都必須有一個 key。spa
按照慣例,查看構造函數:
ReorderableListView({
this.header,
@required this.children,
@required this.onReorder,
this.scrollDirection = Axis.vertical,
this.padding,
this.reverse = false,
}) : assert(scrollDirection != null),
assert(onReorder != null),
assert(children != null),
assert(
children.every((Widget w) => w.key != null),
'All children of this widget must have a key.',
);
複製代碼
瞭解一下各個參數:
剩下兩個就很少說了,都應該瞭解。
既然看完了構造函數,那咱們就能夠分分鐘寫一個 Demo 出來:
class _ReorderableListViewPageState extends State<ReorderableListViewPage> {
List<Color> _data = [
Colors.blue,
Colors.pinkAccent,
Colors.deepPurple,
Colors.orangeAccent
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('ReorderableListViewPage'),
),
body: ReorderableListView(
header: Container(
height: 50,
),
children: _data
.map((s) => Card(
color: s,
key: Key(s.toString()),
child: Container(
width: 300,
height: 100,
),
))
.toList(),
onReorder: (int oldIndex, int newIndex) {
print("$oldIndex --- $newIndex");
}),
);
}
}
複製代碼
ReorderableListView
ReorderableListView
中的 children 爲用顏色定義好的 Card
onReorder
回調中打印兩個參數 oldIndex
& newIndex
運行一下,看一下打印的 log:
能夠看到確實是能打印出新舊兩個 index, 可是這裏有一個很明顯的問題,
咱們你們都知道數組的下標是從 0 開始,能夠看到 第一次是 從 0 到 3,第二次是從 0 到 4,
可是講道理明明應該是 從 0 到 2,從 0 到 3。
那爲何我前兩次移動後的 newIndex 都 +1 了呢?
咱們這裏也不去深究,
既然咱們要移動,那確定也會對源數據進行操做,否則移動也都是假的。
因此,基於這樣的一個 newIndex,咱們只須要這樣:
setState(() {
if(oldIndex < newIndex) {
newIndex -= 1;
}
var temp = _data.removeAt(oldIndex);
_data.insert(newIndex, temp);
});
複製代碼
既然前面說到了 ListView
的刪除,那這裏也必須把它倆組合起來了:
其實代碼很是簡單,固然這也得益於 Flutter 一切皆 Widget,咱們只須要在 Card
上包裹一個 Dismissible
就ok了:
children: _data
.map((s) => Dismissible(
key: Key("dismiss $s"),
child: Card(
color: s,
key: Key(s.toString()),
child: Container(
width: 300,
height: 100,
),
),
))
.toList(),
複製代碼
在 Flutter 當中,咱們能夠封裝不少的 Widget 來爲咱們往後的開發來節省時間,
固然,也不要忘記 Flutter 當中的 Widget 測試