🐡

【Flutter】並び替えができるreorderableListviewの注意点4つ

2023/01/16に公開

TODOアプリなどでリストを作ることがあると思いますが、それらを並び替える機能が欲しいと思ったことありませんか? そんな時はreorderableListViewを利用しましょう。

https://youtu.be/3fB1mxOsqJE

reorderbleListviewの実装は簡単

表示に関してロジックもありますが、正直考える必要はありません。基本的にはコピペでほぼできてしまいます。以下は公式ページのコードを少し編集したものです。個人な好みですが、builderメソッドを使っています。

class ReorderableExample extends StatefulWidget {
  const ReorderableExample({super.key});

  
  State<ReorderableExample> createState() => _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State<ReorderableExample> {
  final List<int> _items = List<int>.generate(50, (int index) => index);

  
  Widget build(BuildContext context) {
    final ColorScheme colorScheme = Theme.of(context).colorScheme;
    final Color oddItemColor = colorScheme.primary.withOpacity(0.05);
    final Color evenItemColor = colorScheme.primary.withOpacity(0.15);

////////////////// ReoderableListViewの部分 //////////////////

    return ReorderableListView.builder(
      padding: const EdgeInsets.symmetric(horizontal: 40),
      itemCount: _items.length,
      itemBuilder: (context, i) {
        return ListTile(
          tileColor: _items[i].isOdd ? oddItemColor : evenItemColor,
          key: Key('$i'), //【注意①】keyが必須になります
          title: Text('Item ${_items[i]}'),
        );
      },
      onReorder: (int oldIndex, int newIndex) {
        //【注意②】並び替え時のロジックは公式にも記載があり、あまり考える必要はありません。
        setState(() {
          if (oldIndex < newIndex) {
            newIndex -= 1;
          }
          final int item = _items.removeAt(oldIndex);
          _items.insert(newIndex, item);
        });
        //【注意③】実際はローカルやAPIを使っての、並び替えたデータの保存処理が必要です。
      },
    );

////////////////// ReoderableListViewの部分 //////////////////

  }
}

注意1 アイテムにはKeyが必要

itemBuilderの後のウィジェットにはkeyが必要となります。 最初はよく分からずReorderableListViewにkeyをつけていましたが、それは誤りなので注意しましょう。

注意2 並び替え時のロジックは考えない

onReorderには並び替え時に呼び出すロジックを記載するのですが、公式のサンプルにはロジックの記載があります。真面目な方だと理解しようと考えるかもしれません。

  if (oldIndex < newIndex) {
    newIndex -= 1;
  }
  final int item = _items.removeAt(oldIndex);
  _items.insert(newIndex, item);

しかし、これは並び替えに必須なロジックであり、いじる必要はありません。特に仕事の場合は納期などもあるので、コピペでも良いと思います。労力としては次に示す保存や表示において使うのが賢明です。

注意3 保存のためにorderをコンストラクターに設ける

個々のアイテムのコンストラクターには、通常nameidcreatedAtなどがありますが、並び順を指定するint型のorderも用意しておきましょう。

また、下記のように初期値や並び替え後の数値を保存すると、次に記載する表示の際に私は楽だと感じました。

新規のアイテムは、order:0,
並び変え後のアイテムは、order:アイテムリストのindex + 1 

注意4 表示順 〜新規分も考えて〜

実際に表示する際には、ロジックも丁寧に考えてあげる必要があります。orderの順に表示するとは言え、2件以上新規作成でアイテムを作ると、order:0で重複してしまうからです。

ついては私は下記のように考えました。

第一優先キー order
第二優先キー createdAt

保存と表示はUIの10倍ぐらいかかった

私の実感ですが、UIの表示は本当にコピペですぐにできます。実際に並び替えができている感じがして楽しいです。しかし、その後のAPIを使って保存したり、新規に表示する際に正しく並び替えて表示する点はかなり手間で、UI作成の10倍くらい時間を使った気がします。

まとめ

並び替え機能を実装する際は、reorderbleListviewを使いましょう。ただし、その後の保存のロジックや、新規画面において正しい順で表示するためには一手間かかるので注意しましょう。

Flutter大学

Discussion