ReorderableListView
を使うとできる
参考: www.youtube.com
@override Widget build(BuildContext context, WidgetRef ref) { List<Widget> _widgets = Iterable<int>.generate(50) .map( (i) => ListTile( key: ValueKey(i), title: Row( children: [ Text( 'Item $i', style: const TextStyle(color: Colors.white), ), const Expanded(child: SizedBox()), const Icon(Icons.reorder), ], ), tileColor: i % 2 == 0 ? Colors.pinkAccent : Colors.purple, ), ) .toList(); return Scaffold( body: ReorderableListView( onReorder: (int oldIndex, int newIndex) { // riverpodとか使ってる人は注意! setState(() { if (oldIndex < newIndex) { newIndex -= 1; } final Widget widget = _widgets.removeAt(oldIndex); _widgets.insert(newIndex, widget); }); }, padding: const EdgeInsets.symmetric(horizontal: 40), children: _widgets, ), ); }
セル全体でドラッグ可能になってしまう。
↓こんな感じにセル全体でドラッグ可能ではなく、アイコンだけにしたい場合がある
ReorderableListView
のbuildDefaultDragHandles
をfalse
- ドラッグ対象のWidgetの親を
ReorderableDragStartListener
よってこうなる
@override Widget build(BuildContext context, WidgetRef ref) { // リストのWidget List<Widget> _widgets = Iterable<int>.generate(50) .map( (i) => ListTile( key: ValueKey(i), title: Row( children: [ Text( 'Item $i', style: const TextStyle(color: Colors.white), ), const Expanded(child: SizedBox()), // このようにReorderableDragStartListenerで囲む ReorderableDragStartListener( index: i, child: const Icon(Icons.reorder), ) ], ), tileColor: i % 2 == 0 ? Colors.pinkAccent : Colors.purple, ), ) .toList(); return Scaffold( body: ReorderableListView( // こいつはデフォルトはtrueだがOFFにするためにfalse buildDefaultDragHandles: false, onReorder: (int oldIndex, int newIndex) { // riverpodとか使ってる人は注意! setState(() { if (oldIndex < newIndex) { newIndex -= 1; } final Widget widget = _widgets.removeAt(oldIndex); _widgets.insert(newIndex, widget); }); }, padding: const EdgeInsets.symmetric(horizontal: 40), children: _widgets, ), ); }