Flutter Key的原理和使用(一) 沒有Key會發生什么
Flutter Key的原理和使用(二) Widget 和 Element 的對應關系
Flutter Key的原理和使用(三) LocalKey的三種型別
Flutter Key的原理和使用(四) GlobalKey 的用法
Flutter Key的原理和使用(五) 需要key的實體:可拖動改變順序的Listview
之前呢,我們介紹了flutter中的幾種key,它們相應的原理和使用方式, 這次就來復習一下,看看一個需要用到key的實體.
ReorderableListView
你可能使用過ListView組件,它可以調整,顯示和滾動專案串列. 但是不能做的一件事就是在串列中移動專案.幸運的是,有ReorderableListView.
ReorderableListView是不個不常用的ListView組件.它是一個用戶可以通過拖動來重新排序其專案的串列組件. 有了它,我們可以通過長按專案來在ListView的滾動方向移動它,將其放在新的位置.
它有一個要求: 所有串列項都必須有一個Key
并且必須實作onReorder方法,它是用戶在重新排序串列時呼叫的回呼方法,看一下沒有實作這個回呼的效果:
ReorderableListView(
children: [
Box(Colors.blue, key: ValueKey(1)),
Box(Colors.green, key: ValueKey(2)),
Box(Colors.red, key: _globalKey),
],
onReorder: (oldIndex, newIndex) {
print('從位置$oldIndex移動到$newIndex');
},
)

可以看到雖然我們交換了紅綠兩個box,但是松手之后UI并沒有變化,就是因為沒有沒有實作onReorder.
onReorder: (oldIndex, newIndex) , 分別有兩個引數,oldIndex和newIndex, 它們代表的含義就是,拖動的widget拖動前和拖動后的index. 看一下列印結果:
從位置2移動到1
說明是從第2個位置移動到了第1個位置(最開始是第0的位置).
每當發生這樣改變的時候,我們就需要把list組件修改.
修改一下我們的代碼,移除舊位置的widget,在新的位置插入它:
final boxList = [
Box(Colors.blue, key: ValueKey(1)),
Box(Colors.green, key: ValueKey(2)),
Box(Colors.red, key: ValueKey(3)),
];
Widget listWidget() {
return ReorderableListView(
children: boxList,
onReorder: (oldIndex, newIndex) {
print('從位置$oldIndex移動到$newIndex');
final box = boxList.removeAt(oldIndex);
boxList.insert(newIndex, box);
},
);
}

這樣就達到了我們移動widget的目的.
但其實將widget從上向下移動的時候,有一個問題,我再移動一下大家看一下:

相應的列印: 從位置0移動到2.
簡單看一下原因:
| index | widget |
|---|---|
| 0 | box1 |
| 1 | box2 |
| 2 | box2 |
我們剛才移動的順序是將box1移動到box2的后面 , 體現在這里就是從0移動到box2后面,也就是說是移動到了2的位置,因為box2的位置是1嘛. 不知道大家有沒有理解.
當然了,如果從起始位置移動到最后,就會出現陣列越界的報錯:
════════ Exception caught by animation library ═════════════════════════════════════════════════════
The following RangeError was thrown while notifying status listeners for AnimationController:
Invalid value: Not in inclusive range 0..2: 3
When the exception was thrown, this was the stack:
#0 List.insert (dart:core-patch/growable_array.dart:11:7)
#1 _MyHomePageState.listWidget.<anonymous closure> (package:flutter_key/home_page.dart:53:17)
#2 SliverReorderableListState._dropCompleted (package:flutter/src/widgets/reorderable_list.dart:646:24)
#3 _DragInfo._dropCompleted (package:flutter/src/widgets/reorderable_list.dart:1163:22)
#4 _DragInfo.startDrag.<anonymous closure> (package:flutter/src/widgets/reorderable_list.dart:1134:9)
...
The AnimationController notifying status listeners was: AnimationController#aca1a(? 0.000; paused; DISPOSED)
════════════════════════════════════════════════════════════════════════════════════════════════════
所以在向下移動的時候,我們要額外處理一下,新的index要減1,之后再進行洗掉和插入操作:
if(newIndex>oldIndex){
newIndex --;
}
橫向串列,就是向右的操作要處理
ReorderableListView的缺點
在拖了幾下之后,發現了幾個缺點:
- 長按才能觸發拖動,容易誤觸.
- ReorderableListView仍然是一個Listview,就是說它是會滾動的,當串列很長可以滾動的時候,會有很多誤操作.
- 一維的ListView,我們都知道listview只能在滾動方向來滑動,ReorderableListView也是一樣,不能上下左右來回拖動.
其實我們可以通過自己來實作一個這樣的組件.
拖動的話,我們可以通過Draggable來實作,它是一個支持拖拽的widget.
為了避免滾動.可以使用Column和Row.
之后有時間, 會實作一個支持拖動的串列組件,來更好的實作這個效果.
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/298402.html
標籤:其他
