Flutter Keyの原理と使い方 (1) Keyがないとどうなるか
Flutter Keyの原理と使い方 (2) WidgetとElementの対応
Flutter Keyの原理と使い方 (3) 3種類のLocalKey
Flutter Keyの原理と使い方 (4) GlobalKeyの使い方
Flutter Keyの原理と使い方 (5) キーが必要な例:ドラッグして順序を変更できるリストビュー
以前、flutter のいくつかのキーとその対応する原理と使用方法を紹介しましたが、今回はキーを使用する必要がある例を復習して見てみましょう。
並べ替え可能なリストビュー
おそらく、アイテムのリストのサイズ変更、表示、スクロールができるコンポーネントを使用したことがあるでしょうListView
。しかし、このコンポーネントでできないことの 1 つは、リスト内のアイテムの移動です。幸いなことに、 がありますReorderableListView
。
ReorderableListView
これはあまり頻繁に使用される ListView コンポーネントではありませんが用户可以通过拖动来重新排序其项目的列表组件
、項目を長押しすることで ListView のスクロール方向に移動し、新しい位置に配置することができます。
これには 1 つの要件があります:すべてのリスト項目には 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');
},
)
赤と緑のボックスを交換しましたが、UI は実装されていないため、手放した後も変化していないことがわかりますonReorder
。
onReorder: (oldIndex, newIndex)
には、oldIndex と newIndex という 2 つのパラメータがあり、ドラッグされたウィジェットのドラッグ前後のインデックスを表します。印刷結果を見てください。
位置 2 から 1 に移動
説明は、2 番目の位置から最初の位置に移動したということです (最初は 0 番目の位置です)。
そのような変更が発生するたびに、リスト コンポーネントを変更する必要があります。
コードを変更して古い位置ウィジェットを削除し、新しい場所に挿入します。
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);
},
);
}
これで、ウィジェットを移動するという目的は達成されました。
しかし、実際には、ウィジェットを上から下に移動するときに問題が発生します。もう一度移動させて見てみましょう。
対応する印刷: 位置 0 から 2 に移動します。
理由を見てください:
索引 | ウィジェット |
---|---|
0 | ボックス1 |
1 | ボックス2 |
2 | ボックス2 |
先ほど移動した順序は、box1 を box2 の後ろに移動することです。ここでは、box2 の位置が 1 であるため、0 から box2 の後ろ、つまり 2 の位置に反映されています。もちろん
、開始位置から最後まで移動すると、配列範囲外エラーが発生します。
════════ 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)
════════════════════════════════════════════════════════════════════════════════════════════════════
したがって、下に移動するときは、追加の処理を実行する必要があり、新しいインデックスを 1 だけデクリメントしてから、削除して挿入する必要があります。
if(newIndex>oldIndex){
newIndex --;
}
水平リスト、つまり右側の操作を処理する必要があります
ReorderableListView の欠点
何度かドラッグした結果、いくつかの欠点が見つかりました。
- 長押しするとドラッグが開始され、誤ってタッチしやすくなります。
- ReorderableListView はリストビューなのでスクロール可能ですが、リストが長くてスクロール可能だと誤操作が多くなります。
- 1 次元の ListView の場合、リストビューはスクロール方向にのみスライドできることは誰もが知っていますが、同じことが ReorderableListView にも当てはまり、上下左右に前後にドラッグすることはできません。
実はこのようなコンポーネントは自分で実装することができます
ドラッグすればDraggable
それを介して実装できます ドラッグアンドドロップをサポートするウィジェットですスクロール
を避けるためにColumn
と を使用できますRow
後で時間があるときに、この効果をより適切に実現するために、ドラッグをサポートするリスト コンポーネントが実装される予定です。