MENU

Flutter ListViewの使い方|初心者向けに一覧表示をやさしく解説

Flutter ListViewの使い方|初心者向けに一覧表示をやさしく解説

Flutter ListView 使い方を覚えるなら、まずはListViewListView.builderの違いを理解するのがおすすめです。少ない固定データならListView、件数が多いデータならListView.builderを使い分けると、読みやすく効率的な画面を作れます。この記事では、3件のメニュー表示からデータ連動の一覧まで順番に説明します。

初心者の疑問: ListViewは、画面をスクロールさせるためだけのウィジェットですか? 答え: スクロールに加えて、縦または横方向へウィジェットを並べる役割も持っています。

目次

ListViewとは

ListViewは、子ウィジェットを一方向に並べるスクロール可能なウィジェットです。Flutter公式APIでは、標準のListView、遅延生成するListView.builder、区切り線を作りやすいListView.separatedなどのコンストラクターが用意されています。

たとえば、メニューや設定項目のように、同じ画面に複数の項目を縦に並べたいときに向いています。

最初に作る固定の一覧

項目数が少なく、表示内容が決まっているなら、childrenにウィジェットを直接書く方法が分かりやすいです。ListTileを使うと、アイコンとタイトルを持つ行を簡単に作れます。

import 'package:flutter/material.dart';

class BasicListPage extends StatelessWidget {
  const BasicListPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('メニュー')),
      body: ListView(
        children: const [
          ListTile(
            leading: Icon(Icons.map),
            title: Text('地図'),
          ),
          ListTile(
            leading: Icon(Icons.photo_album),
            title: Text('アルバム'),
          ),
          ListTile(
            leading: Icon(Icons.phone),
            title: Text('電話'),
          ),
        ],
      ),
    );
  }
}

ListViewは内容が画面の高さを超えるとスクロールできます。Scaffoldbodyに置く形は、最初の動作確認にも適しています。

ポイント: まずは3〜5項目の固定リストで、スクロールと行の見た目を確認してからデータ連動へ進むと、エラーの場所を特定しやすくなります。

データから一覧を作るListView.builder

実際のアプリでは、商品、メッセージ、検索結果などをList<String>やモデルのリストから表示することが多くなります。その場合はListView.builderを使います。

class ProductListPage extends StatelessWidget {
  ProductListPage({super.key});

  final List<String> products = const [
    'ノートパソコン',
    'ワイヤレスマウス',
    'キーボード',
    'USBハブ',
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('商品一覧')),
      body: ListView.builder(
        itemCount: products.length,
        itemBuilder: (context, index) {
          return ListTile(
            leading: CircleAvatar(child: Text('${index + 1}')),
            title: Text(products[index]),
          );
        },
      ),
    );
  }
}

itemCountは表示する件数、indexは0から始まる項目番号です。products[index]で、現在の行に対応するデータを取り出しています。

Flutter公式APIによると、ListView.builderは表示が必要な子を必要に応じて作るため、項目数が多い一覧や、件数が増える一覧に適しています。itemCountを指定しておくと、スクロールバーの大きさや終了位置も正しく扱いやすくなります。

初心者の疑問: indexは1から始まりますか? いいえ、Dartのリストと同じく0から始まります。画面上の番号を1から表示したいときだけ、例のようにindex + 1を使います。

ListViewとListView.builderの使い分け

作りたい一覧向いている方法理由
項目が数個で固定ListViewコードを直接読めて簡単
配列のデータを表示ListView.builderindexで繰り返し表示できる
件数が多い、増える可能性があるListView.builder子ウィジェットを必要な分だけ生成しやすい
行と行の間に区切りを入れるListView.separated区切り用の処理を分けて書ける

比較ポイント: 「今は3件だからListView」ではなく、今後APIやデータベースから件数が増えるかも判断材料にしましょう。増えるなら、最初からListView.builderにしておくと作り直しを減らせます。

区切り線を入れるListView.separated

行の間にDividerなどを入れたいときは、ListView.separatedが便利です。項目を作るitemBuilderと、区切りを作るseparatorBuilderを分けられます。

ListView.separated(
  itemCount: products.length,
  itemBuilder: (context, index) {
    return ListTile(title: Text(products[index]));
  },
  separatorBuilder: (context, index) {
    return const Divider(height: 1);
  },
)

最後の項目の後ろに区切り線を追加したくない場合も、separatorBuilderなら「項目の間」だけに表示できます。

横向きにスクロールする

初期状態のscrollDirectionは縦方向です。カードを横に並べたいときはAxis.horizontalを指定します。

ListView.builder(
  scrollDirection: Axis.horizontal,
  itemCount: products.length,
  itemBuilder: (context, index) {
    return SizedBox(
      width: 160,
      child: Card(
        child: Center(child: Text(products[index])),
      ),
    );
  },
)

横向きでは、子ウィジェットに幅を指定しないとレイアウトが分かりにくくなります。SizedBoxConstrainedBoxでカードのサイズを決めておくと安定します。

初心者がつまずきやすいエラー

`RangeError`が出る

itemCountと、実際のリストの長さが合っていない可能性があります。たとえばitemCount: 10なのに、データが3件しかない状態でproducts[index]を呼ぶと、存在しない番号を参照してしまいます。

基本は次のように、同じリストのlengthを使います。

itemCount: products.length

`ListView`が表示されない、または高さのエラーになる

Columnの中にスクロールビューを置くとき、縦方向の高さが決まらないことがあります。画面の残りを使いたいならExpandedで包みます。

Column(
  children: [
    const Text('商品一覧'),
    Expanded(
      child: ListView.builder(
        itemCount: products.length,
        itemBuilder: (context, index) =>
            ListTile(title: Text(products[index])),
      ),
    ),
  ],
)

`shrinkWrap: true`をどこでも使う

shrinkWrapは、内容に合わせてスクロールビューの大きさを決めたいときに使います。ただし、長い一覧を別のスクロールビューの中に入れる構成では、レイアウトや処理の負担が増えやすくなります。

注意: ListViewSingleChildScrollViewの中に重ねる前に、画面全体を1つのListViewで表せないか検討しましょう。スクロール方向が重複すると、操作しにくい画面になりやすいです。

空の一覧も先に考える

データが0件のときに、空白の画面だけを表示すると、読み手は「読み込みに失敗したのか」と迷います。データがある場合とない場合で表示を切り替えます。

Widget buildBody(List<String> products) {
  if (products.isEmpty) {
    return const Center(child: Text('表示できる商品がありません'));
  }

  return ListView.builder(
    itemCount: products.length,
    itemBuilder: (context, index) =>
        ListTile(title: Text(products[index])),
  );
}

この考え方は、API通信中のローディング表示や、通信失敗時の再試行ボタンにも広げられます。

チェックリスト: itemCountがリストの長さと一致している/0件の表示を用意した/縦横の向きを決めた/親の高さが決まっている/長い一覧ではbuilderを使っている。

まとめ:まずはbuilderで実用的な一覧を作る

Flutter ListViewの使い方で大切なのは、表示するデータの性質に合わせてコンストラクターを選ぶことです。

  1. 固定された少数の項目はListViewで直接並べる
  2. 配列やAPIのデータはListView.builderで生成する
  3. 区切り線が必要ならListView.separatedを使う
  4. itemCountには元データのlengthを指定する
  5. 空データ、親の高さ、shrinkWrapの使い方を確認する

次にやること: まずはList<String>を4件用意し、ListView.builderで表示してみましょう。次にListTileのタップ処理を追加すると、一覧から詳細画面へ進むアプリの形に近づきます。

参考にした公式情報

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

meibuのアバター meibu 中年ブロガー

【このブログを書いている人】
こんにちは、meibuです!
読者の「ちょっと気になる」「でも難しそう…」をやさしく解決したくてこのブログを始めました。

🔹プロフィールまとめ
◎ 本業は運送業の管理職
 → 現場からマネジメントまで幅広く経験

● 趣味はパソコン・ランニング・情報収集

●興味のあるテーマ:
 副業 / ChatGPT

● 発信スタイルは…
 → 「初心者にもわかりやすく」+「図解・たとえ話も使って解説」

● ブログの目的:
 日常に“ちょっと得する”選択肢を増やすこと
管理職の悩みを最近少し書いています

🔸こんな人に読んでほしい!
ChatGPTってなに?使い方がわからない方
管理職の職位に悩んでいる人
忙しいけど、自分の未来のために動きたい方

● 「読んでよかった!」と思える情報を、これからもコツコツ更新していきます!
当ブログはアフェリエイト広告を利用しています。

コメント

コメントする

CAPTCHA


目次