ReorderableListView の基本
Flutter でリストのドラッグ&ドロップによる並び替えを実装するには、ReorderableListView を使用します。
基本的な実装
ReorderableListView(
onReorderItem: (oldIndex, newIndex) {
HapticFeedback.lightImpact(); // 触覚フィードバック
setState(() {
final item = _items.removeAt(oldIndex);
_items.insert(newIndex, item);
});
},
children: [
for (final item in _items)
ListTile(
key: ValueKey(item.id),
title: Text(item.name),
leading: const Icon(Icons.drag_handle),
),
],
)
onReorderItem で移動元と移動先のインデックスを受け取り、_items の要素を並べ替えます。
従来の onReorder とは異なり、onReorderItem では newIndex の補正が自動で行われるため、手動で newIndex-- をする必要はありません。
onReorder を使用する場合の index 補正
従来の onReorder を使用する場合は、移動元の要素を削除するとリストの要素数が1つ減るため、移動先のインデックスを補正する必要があります。
onReorder: (oldIndex, newIndex) {
setState(() {
if (newIndex > oldIndex) {
newIndex--;
}
final item = _items.removeAt(oldIndex);
_items.insert(newIndex, item);
});
},
移動方向ごとの補正は次のとおりです。
| 移動方向 | インデックスの補正 |
|---|---|
| 上方向 | 不要 |
| 下方向 |
newIndex-- が必要 |
※ この補正は従来の onReorder を使用する場合のものです。onReorderItem では不要です。
各アイテムに一意な key を指定する
ReorderableListView の各子 Widget には key が必要です。
ListTile(
key: ValueKey(item.id),
title: Text(item.name),
)
ValueKey(item.id) のように、各アイテムを一意に識別できる値を指定します。
item.id が重複していると、正しくアイテムを識別できないため注意が必要です。
空リストの表示
リストが空の場合は、並び替え用の UI ではなく、空の状態を示す Widget を表示すると親切です。
body: _items.isEmpty
? const EmptyView(
title: 'アイテムがありません',
message: 'アイテムを追加してから並び替えてください',
)
: ReorderableListView(
onReorderItem: (oldIndex, newIndex) {
setState(() {
final item = _items.removeAt(oldIndex);
_items.insert(newIndex, item);
});
},
children: [
for (final item in _items)
ListTile(
key: ValueKey(item.id),
title: Text(item.name),
),
],
),
EmptyView は独自に定義した Widget を想定しています。
確定ボタンを押すまで親画面に変更を反映しない
並び替え画面で編集した結果を、確定ボタンを押したタイミングで親画面に返す設計もできます。
FilledButton(
onPressed: () => Navigator.pop(context, _items),
child: const Text('確定'),
)
Navigator.pop(context, _items) で画面を閉じ、並び替え後のリストを呼び出し元に返します。
このコード自体は Firestore への保存を行いません。保存が必要な場合は、親画面で返されたリストを受け取り、Firestore への保存処理を実行します。
このようにすることで、並び替え中はローカルのリストのみを更新し、確定時に結果を反映する設計にできます。
ポイント
-
ReorderableListView:ドラッグ&ドロップによる並び替えを実現する Widget -
ValueKey(item.id):各アイテムを一意に識別するためのkey -
onReorderItem:並び替え後のインデックスを受け取るコールバック -
HapticFeedback.lightImpact():軽い触覚フィードバックを発生させる -
setState:並び替え後に UI を再描画する -
Navigator.pop(context, _items):編集結果を親画面に返す
まとめ
ReorderableListView と一意な key を組み合わせることで、ドラッグ&ドロップによるリストの並び替えを実装できます。
また、並び替え結果をローカルで管理し、確定時に親画面へ返すことで、画面上の編集とデータの保存処理を分離できます。
なお、onReorderItem は Flutter 3.44 で安定版に導入された API です。それ以前の Flutter バージョンでは、従来の onReorder を使用してください。