成果物
デモ
Web版だとReorderableListViewのみ挙動が異なります。
(右側の並び替えアイコンを長押ししないと並び替えできない。)
ソースコード
ListView
並べ替えできるGridView
以下のパッケージを使いました。
使い方もReorderableListViewとほとんど同じで、非公式とは思えないほど使いやすかったです。
Sliver対応のSliverReorderableGridクラスもあります。
ReorderableGridView の使い方
- ほとんど
ReorderableListViewと同じ。 -
itemBuilderに並べたい要素を返す関数を指定し、各要素にはユニークなkeyを指定します。 - コードにはないですが、こちらも
proxyDecoratorを指定することでドラッグ中の要素の見た目を変えることができます。 -
gridDelegateにはGridViewでおなじみのSliverGridDelegateWithFixedCrossAxisCountを指定。(他にもあった気がします) -
ReorderableListViewと同じく、.builderを使わない書き方もOK。
class ReorderableGridViewSample extends ConsumerWidget {
const ReorderableGridViewSample({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final items = ref.watch(itemsProvider);
return Scaffold(
appBar: AppBar(),
body: ReorderableGridView.builder(
itemBuilder: (_, index) => ItemCard(
items[index],
key: Key('$index'), // 各要素にユニークなKeyをつける必要がある
),
itemCount: items.length,
onReorder: (int oldIndex, int newIndex) =>
_onReorder(items, oldIndex, newIndex),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: kIsWeb ? 4 : 2,
),
),
);
}
void _onReorder(List<Item> items, int oldIndex, int newIndex) {
final item = items.removeAt(oldIndex);
items.insert(newIndex, item);
}
}
SliverReorderableGrid の使い方
- こちらもほぼ
SliverReorderableListと同じ。すごい。 - ドラッグリスナーとしては
ReorderableGridDragStartListenerまたはReorderableGridDelayedDragStartListenerが用意されており、各要素をいずれかでラップする。 - ユニークな
keyは並べたい要素自体(ここではItemCard)ではなく上記のいずれかのリスナーに付ける必要があるので注意。
class SliverReorderableGridPage extends ConsumerWidget {
const SliverReorderableGridPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final items = ref.watch(itemsProvider);
return Scaffold(
body: CustomScrollView(
slivers: [
const SliverAppBar(),
SliverReorderableGrid(
// SliverReorderableListと同様、こちらも各要素を
// ReorderableGridDragStartListener または ReorderableGridDelayedDragStartListenerで
// ラップする必要がある。
itemBuilder: (_, index) => ReorderableGridDelayedDragStartListener(
index: index,
key: Key('$index'),
child: ItemCard(
items[index],
key: Key('$index'), // 各要素にユニークなKeyをつける必要がある
),
),
itemCount: items.length,
onReorder: (int oldIndex, int newIndex) =>
_onReorder(items, oldIndex, newIndex),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: kIsWeb ? 4 : 2,
),
proxyDecorator: (widget, _, __) {
return Opacity(opacity: 0.5, child: widget);
},
),
],
),
);
}
void _onReorder(List<Item> items, int oldIndex, int newIndex) {
final item = items.removeAt(oldIndex);
items.insert(newIndex, item);
}
}
不具合?
- そんなに大したことではありませんが、ドラッグ中に元の位置に戻せないです(
v1.0.3時点)。