FlutterのListViewを使ったスクロール可能なリストの基本から応用まで

モバイル開発

はじめに

皆さんがFlutterでアプリを開発しているときに、画面をスクロールして大量のデータを表示する必要が出てくることがあるのではないでしょうか。 そんなときに役立つのが、ListView という便利なウィジェットです。 スクロール可能なリストを簡単に扱えるため、チャットアプリや商品一覧など、さまざまな場面で頻繁に利用されます。 一方で、具体的にどうコードを書けばよいか迷ってしまう方も多いかもしれません。 そこでこの記事では、ListViewの基礎から応用的な内容までをまとめてお伝えします。

ListViewとは何か?

FlutterにおけるListView は、縦方向や横方向にスクロールできるリスト表示を実現するウィジェットです。 単純にスクロール表示をするだけでなく、配置する要素の数が動的に増減する場合にも対応できます。 リストの項目が画面外にあるときには描画を遅延するなど、効率的なリソース管理が可能となっています。 したがって、データ数が多い場面でも比較的スムーズな操作性を保ちやすいです。 初めてFlutterを触る人にとっては、最初のハードルが少なくて使いやすいリスト表示の選択肢と言えるでしょう。

ListViewが活躍するシーン

皆さんは、SNSのタイムラインやショッピングサイトの商品一覧など、長いリストを見た経験があるのではないでしょうか。 こうした画面は、ページを切り替えずに下方向へスクロールしてどんどん項目を表示することが多いです。 Flutterでこうした仕組みを作る際、ListViewが最初に検討されることが一般的です。 例えば、APIから受け取ったデータを一覧で並べたいときや、チャットアプリでメッセージを連続して表示したいときなどが典型的な利用例です。 つまり、要素が多く、かつ画面をスムーズにスクロールして使いたいシーンではListViewがよく選ばれます。

基本的な実装

FlutterでListViewを使うときには、大きくわけて2通りの書き方を覚えておくと便利です。 1つ目は、静的なリストを表示したい場合に使われるListView コンストラクタの方法です。 2つ目は、動的にリストを生成できるListView.builder です。 前者は要素数が決まっていて、あまり長くならない場合に使いやすいでしょう。 後者は画面に表示される範囲に応じて必要な部分だけを生成するため、たくさんのデータを扱うケースでも動作が軽くなりやすいです。

単純なListViewの例

まずは、いくつかのテキストを縦に並べたいときのコード例を見てみましょう。 以下のように書くと、単純に複数のウィジェットを上下に並べてスクロールができるようになります。

import 'package:flutter/material.dart';

class SimpleListViewExample extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Simple ListView'),
      ),
      body: ListView(
        children: [
          ListTile(
            title: Text('Item 1'),
            subtitle: Text('Subtext 1'),
          ),
          ListTile(
            title: Text('Item 2'),
            subtitle: Text('Subtext 2'),
          ),
          ListTile(
            title: Text('Item 3'),
            subtitle: Text('Subtext 3'),
          ),
        ],
      ),
    );
  }
}

ListTileウィジェットを使うと、テキストを見やすくレイアウトできます。 このように、リストの要素が数個しかない場合は単純なListViewの使い方で問題ありません。

ListView.builderを使った動的リスト

実際の開発では、要素の数が多かったり、APIから取得したデータをもとにリストを描画するケースが一般的です。 このような場合には、ListView.builder を使うと、必要な範囲だけウィジェットを作成できるため効率が良いです。 下のコード例では、アイテムのタイトルにインデックス番号を表示するようにしています。

import 'package:flutter/material.dart';

class DynamicListViewExample extends StatelessWidget {
  final List<String> items = List.generate(100, (index) => 'Item $index');

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Dynamic ListView'),
      ),
      body: ListView.builder(
        itemCount: items.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(items[index]),
          );
        },
      ),
    );
  }
}

上記のようにitemBuilderを使うことで、必要な要素が生成されるたびにコールバックが呼ばれます。 その結果、データ数が多くても無駄な描画を減らしてスムーズにスクロールできるようになります。

パフォーマンスを意識したListView

ListViewは便利ですが、数千件以上のデータを扱うときにはパフォーマンス面を考慮する必要があります。 例えば、画面に表示されていないウィジェットを生成し続けると、メモリ使用量や描画時間が増えてアプリの動作が重くなるかもしれません。 ListView.builderは必要な部分だけをレンダリングする仕組みを備えているため、多くの場合は問題になりにくいです。 ただし、大量のデータを取り扱うなら、ListView.separated でリスト間の区切りを効率的に管理する方法も検討できるでしょう。

複数のListViewを同じ画面内でネストすると、意図しないスクロール挙動を起こすことがよくあります。 画面全体の構造を見直して、必要に応じてSingleChildScrollViewなどほかのウィジェットと組み合わせる工夫も考えてみましょう。

また、デザインの観点から、表示する要素が高度にカスタマイズされる場合には、Layout構造を複雑にし過ぎないことが大切です。 画面にフィットする程度のシンプルなUIから始め、必要に応じて要素を追加していくと負荷を管理しやすいでしょう。

実務でよくある活用例

実務の現場では、ユーザーがスクロールして下まで到達したら次のデータをロードするというような仕組みを作ることが多いです。 たとえば、ニュースアプリやSNSフィードでは、初期ロード後も追加で項目を読み込む「無限スクロール」が求められるケースがあります。 ListView.builderのitemBuilder内でインデックス番号を確認し、リストの末尾付近に来たタイミングでAPIを呼ぶように実装すれば、自然な「次のアイテムのロード」を実現できます。 また、項目同士の間に広告や区切り線を表示するといったカスタマイズも、ListTileやDividerを組み合わせれば簡単に実装可能です。 こうした細かい仕掛けが、ユーザーにとって使いやすい画面を作るうえで重要になってきます。

画面全体の構成を考えたうえで、必要な場所に最適なListViewを配置すると複雑なUIも比較的管理しやすいです。 無理に1つのListViewで全てを済ませるより、要件に合わせてリストを分割して使う方法も視野に入れましょう。

よくあるトラブルシューティング

開発中には、リストをタブやスワイプページの中に入れるなど、ListViewを複合的に使う場面も少なくありません。 このときにスクロールができなくなったり、スクロールが重複したりする問題が起きることがあります。 そんなときは、主に以下の点に注意してみると良いでしょう。

  • 複数のスクロール方向が競合していないか
  • ListViewを他のスクロール系ウィジェット(SingleChildScrollViewなど)と重ねていないか
  • shrinkWrapやphysicsなどのプロパティで挙動を変えすぎていないか

無理にネストを増やさず、シンプルに記述することで問題が解消する場合は多いです。 また、レイアウトエラーやオーバーフローが起きるときは、ExpandedやFlexibleといったウィジェットを活用して、画面サイズに応じたレイアウトを調整するのも一つの方法です。

まとめ

ここまで、FlutterでListView を使うときの基本から活用例までを紹介してきました。 ListViewは、アプリにおけるリスト表示の要ともいえる存在で、特に数が多いデータを扱う場面では欠かせません。 単純な配置にはListViewコンストラクタ、動的なリストにはListView.builder、区切り線が必要ならListView.separatedなど、複数の使い方を使い分けることで開発効率を高められます。 一方で、スクロールが複数重なる場合はネスト構造を再考するなど、実装の工夫も大切です。 初心者の皆さんはまず単純な例から試してみて、自分のアプリに合わせた書き方を少しずつ覚えていくと良いでしょう。

Dartをマスターしよう

この記事で学んだDartの知識をさらに伸ばしませんか?
Udemyには、現場ですぐ使えるスキルを身につけられる実践的な講座が揃っています。