🤷‍♂️

【Flutter】ReorderableListViewで困ったこと

2023/02/24に公開

https://api.flutter.dev/flutter/material/ReorderableListView-class.html

ReorderableListViewは、リストビューの項目をドラッグして並び替えることができるウィジェットです。
使用時に思った通りに実装するのがなかなか難しかったので解決法をまとめておきます。

paddingも一緒にドラッグしてしまう

itemBuilder: (context, index) {
	return Padding(
	  key: Key(index.toString()),
	  padding: const EdgeInsets.all(8.0),
	  child: ListTile(
	    tileColor: Colors.grey[300],
	    style: ListTileStyle.list,
	    title: Center(
	      child: Text('${snapshot.data![index].id}'),
	    ),
	  ),
	);
},

アイテム間に余白が欲しい時、ListTileにpaddingを付けると・・・

こんな感じで余白までつまんじゃいます。
結構不恰好なのでなんとかしたいところです。

ColumnでSizedBox上に置いたりいろいろ試しましたが結果は同じでした。

解決法:separatorに余白を入れる

要素の間に置きたいウィジェットを指定できるListView.separatedみたいなのが欲しいんですが、
ReorderableListView.separatedは無いんですよね。
https://api.flutter.dev/flutter/widgets/ListView/ListView.separated.html

なので作るしかないんですが、有難いことに既に書いてくれた方がいました。
https://github.com/flutter/flutter/issues/76706#issuecomment-1067992802

CustomReorderableListView.separatedを別ファイルにコピペ、
separatorBuilderにSizedBoxを追加して...

    CustomReorderableListView.separated(
      padding: const EdgeInsets.symmetric(horizontal: 8.0),
      itemCount: snapshot.data!.length,
      itemBuilder: (context, index) {
	return ListTile(
	  key: Key(index.toString()),
	  tileColor: Colors.grey[300],
	  style: ListTileStyle.list,
	  title: Center(
	    child: Text('${snapshot.data![index].id}'),
	  ),
	);
      },
      separatorBuilder: (BuildContext context, int index) {
	return const SizedBox(
	  height: 8.0,
	);
      },
      onReorder: (int oldIndex, int newIndex) {
	final Todo item = snapshot.data!.removeAt(oldIndex);
	snapshot.data!.insert(newIndex, item);
      },
    );

これで思い通りになりました。
separatorBuilderにSizedboxではなくDividerなど透明じゃないものを挟むと、separatorも動いてるのがわかっちゃうのでまた別の解決法が必要ですね。

tileColorが置いてきぼりになる

ドラッグ時にListTileの中身だけがニュっと出てtilecolorに設定したグレーだけが置いてきぼりになっちゃってます。気になりますよね。

itemBuilderの中身はさっきと同じListTileが一番上に来てるコードです。

itemBuilder: (context, index) {
	return ListTile(
	  key: Key(index.toString()),
	  tileColor: Colors.grey[300],
	  style: ListTileStyle.list,
	  title: Center(
	    child: Text('${snapshot.data![index].id}'),
	  ),
	);
},

解決法:Cardの中に入れる

itemBuilder: (context, index) {
	return Card(
	  //keyをCardに移動
	  key: Key(index.toString()),
	  margin: EdgeInsets.zero,
	  child: ListTile(
	    style: ListTileStyle.list,
	    tileColor: Colors.grey[300],
	    title: Center(
	      child: Text(
		'${snapshot.data![index].id}',
	      ),
	    ),
	  ),
	);
},

無事成功しましたが、Cardで解決した理由は全く分かりません。
Containerで囲った時は意味が無かったんですが何故かCardでできたんですよね。

解決したのはリストアイテムに影が欲しかったので付けた時に偶然発見したからです。
ReorderableListView、クセがすごい

Discussion