Flutterで10個ずつ追加されるListViewBuilderを自作した話

2024/12/05に公開

ListViewBuilderで自作

flutter_hooksを利用しています。

https://pub.dev/packages/flutter_hooks

50個の値が入ったリストを作成。
初期表示は10個とします。

スクロールが最下層に行った場合、(この場合だと10個のリスト表示がされた)
useEffectを利用して再度リストに今表示している内容から+10個のリストを追加する様な形です。

hooksを使用していて下記パッケージを利用していたのですが、ある一部分のみ利用できない画面があったので自作しました。

https://pub.dev/packages/riverpod_paging_utils

class CustomScrollList extends HookWidget {
  
  Widget build(BuildContext context) {
  // 一度に追加するアイテム数
    final int increment = 10;

    // 全データリスト(50件のデータを仮定)
    final fullItemList =  List.generate(50, (index) => Item('Item ${index + 1}'));

    // 表示用リストの状態管理
    final displayedItems = useState<List<Item>>([]);

    // ScrollControllerの初期化
    final scrollController = useScrollController();

   // データの追加読み込み関数
     void addItems() {
      /// これ以上リストが無い場合
      if (displayedItems.value.length >= fullItemList.value.length) {
        return;
      }

      /// 次のリスト10個作成
      var nextCount = displayedItems.value.length + increment;
      if (nextCount > fullItemList.value.length) {
        nextCount = fullItemList.value.length;
      }

      /// リストの結合 表示しているリスト+追加で表示するリストを加える
      displayedItems.value = [
        ...displayedItems.value,
        ...fullItemList.value.getRange(dispItem.value.length, nextCount),
      ];
    }
  // スクロールを監視
    useEffect(() {
      void scrollListener() {
        // 最下層に到達したかどうかを判別
        if (scrollController.position.pixels >=
            scrollController.position.maxScrollExtent) {
          // 最下層に到達
          addItems();
        }
      }
      //スクロールのたびに確認
      scrollController.addListener(scrollListener);
      // 処理削除
      return () => scrollController.removeListener(scrollListener);
    }, [
      scrollController,
    ]);

    return Scaffold(
      appBar: AppBar(title: Text('Infinite Scroll with HookWidget')),
      body: ListView.builder(
        controller: scrollController,
        itemCount: displayedItems.value.length,
        itemBuilder: (context, index) {
            final item = displayedItems.value[index];
            return ListTile(
              title: Text(item.title),
            );
          }
        },
      ),
    );
  }
}
/// リスト表示用
class Item {
  final String title;
  Item(this.title);
}

自作してみましたが、もう少しカスタムして見栄え良くしたりはできそうです。
インジケータがないので読込み時はそうするとか工夫できそう。

以上!

Discussion