Flutter ListView とスクロール

ListView は Flutter で最もよく使われるスクロールリストウィジェットで、スクロール可能なコンテンツリストを表示するために使用されます。


ListView の基本用法

例:ListView の基本用法

// 方法1: children パラメータ(少量の項目に適しています)
ListView(
  children: [
    ListTile(title: Text('第1項')),
    ListTile(title: Text('第2項')),
    ListTile(title: Text('第3項')),
  ],
)

// 方法2: ListView.builder(大量または無限リストに適しています)
ListView.builder(
  itemCount: 100,
  itemBuilder: (context, index) {
    return ListTile(title: Text('第 ${index + 1} 項'));
  },
)

// 方法3: ListView.separated(セパレータ付き)
ListView.separated(
  itemCount: 10,
  separatorBuilder: (context, index) => const Divider(),  // 区切り線
  itemBuilder: (context, index) {
    return ListTile(title: Text('第 ${index + 1} 項'));
  },
)

ListView のよく使う属性

属性説明
scrollDirectionスクロール方向。デフォルトは Axis.vertical(垂直)
reverse逆方向にスクロールするかどうか
paddingリストのパディング
itemExtent項目の高さを固定し、パフォーマンスを向上させます
prototypeItemプロトタイプ項目。高さの計算に使用します

例:横方向の ListView

// 横スクロールリスト
SizedBox(
  height: 120,  // 高さを設定する必要があります
  child: ListView.builder(
    scrollDirection: Axis.horizontal,  // 横スクロール
    itemCount: 20,
    itemBuilder: (context, index) {
      return Container(
        width: 100,
        margin: const EdgeInsets.symmetric(horizontal: 8),
        color: Colors.blue[100],
        child: Center(
          child: Text('項目 $index'),
        ),
      );
    },
  ),
)

GridView - グリッドレイアウト

GridView は二次元のグリッドリストを作成するために使用されます。

例:GridView の使い方

// GridView.count - 固定の列数
GridView.count(
  crossAxisCount: 3,  // 3 列
  children: List.generate(20, (index) {
    return Container(
      margin: const EdgeInsets.all(4),
      color: Colors.blue[100],
      child: Center(child: Text('${index + 1}')),
    );
  }),
)

// GridView.builder - 動的に構築
GridView.builder(
  gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 4,  // 4 列
    mainAxisSpacing: 8,  // 垂直方向の間隔
    crossAxisSpacing: 8,  // 水平方向の間隔
    childAspectRatio: 1,  // アスペクト比
  ),
  itemCount: 50,
  itemBuilder: (context, index) {
    return Container(
      color: Colors.green[100],
      child: Center(child: Text('${index + 1}')),
    );
  },
)

// GridView.extent - 自動適応列数
GridView.extent(
  maxCrossAxisExtent: 150,  // 最大列幅
  children: List.generate(20, (index) {
    return Container(
      margin: const EdgeInsets.all(4),
      color: Colors.orange[100],
      child: Center(child: Text('${index + 1}')),
    );
  }),
)

スクロール制御

ScrollController を使用してスクロール位置を制御できます。

例:スクロール制御

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

  @override
  State<ScrollExample> createState() => _ScrollExampleState();
}

class _ScrollExampleState extends State<ScrollExample> {
  // スクロールコントローラーを作成
  late ScrollController _controller;

  @override
  void initState() {
    super.initState();
    _controller = ScrollController();
    // スクロールイベントを監視
    _controller.addListener(() {
      print('スクロール位置: ${_controller.offset}');
    });
  }

  @override
  void dispose() {
    // コントローラーを破棄
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // トップへスクロールボタン
        ElevatedButton(
          onPressed: () {
            // トップへスクロール
            _controller.animateTo(
              0,
              duration: const Duration(milliseconds: 500),
              curve: Curves.easeInOut,
            );
          },
          child: const Text('トップへスクロール'),
        ),
        // リスト
        Expanded(
          child: ListView.builder(
            controller: _controller,  // コントローラーをバインド
            itemCount: 100,
            itemBuilder: (context, index) {
              return ListTile(title: Text('第 ${index + 1} 項'));
            },
          ),
        ),
      ],
    );
  }
}

Slivers 高度なスクロール

CustomScrollView と Slivers を組み合わせることで、より複雑なスクロール効果を実現できます。

例:Slivers での折りたたみ効果

// 折りたたみアプリバー付きスクロールビュー
CustomScrollView(
  slivers: [
    // 折りたたみアプリバー
    SliverAppBar(
      expandedHeight: 200,  // 展開時の高さ
      pinned: true,  // 上部に固定
      flexibleSpace: FlexibleSpaceBar(
        title: const Text('折りたたみタイトル'),
        background: Container(
          decoration: BoxDecoration(
            gradient: LinearGradient(
              colors: [Colors.blue, Colors.purple],
              begin: Alignment.topLeft,
              end: Alignment.bottomRight,
            ),
          ),
        ),
      ),
    ),
    // リスト内容
    SliverList(
      delegate: SliverChildBuilderDelegate(
        (context, index) => ListTile(title: Text('第 ${index + 1} 項')),
        childCount: 30,
      ),
    ),
  ],
)

// グリッド Sliver
CustomScrollView(
  slivers: [
    const SliverAppBar(
      title: Text('画像グリッド'),
      pinned: true,
    ),
    SliverGrid(
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
      ),
      delegate: SliverChildBuilderDelegate(
        (context, index) => Card(
          child: Image.network('https://picsum.photos/200?$index'),
        ),
        childCount: 20,
      ),
    ),
  ],
)

Slivers は、多数のスクロール項目を処理するための効率的な方法を提供します。可視領域の項目のみをレンダリングするため、優れたパフォーマンスを提供します。

その他の拡張