LoginSignup
5
6

More than 3 years have passed since last update.

Sliverで(動的な)画像のグリッドを実装する

Posted at

概要

公式のSliverGridの動画に出てくる↓を、画像を展開するグリッドとして実装します。動的なコンテンツ表示でよく使うやつですね。
雑にググったら色付きのタイルを並べてるサンプルは出てくるけど画像を動的に並べるコードがあんまり出てこなかったので書きました。

image.png

前提となるウィジェット

Scaffoldと、Sliverを使う時のお約束であるCustomScrolViewを置きます。

Scaffold(
  body: CustomScrolView()
)

画面はまだ真っ白です。

image.png

公式の仰せのままにとりあえずSliverGridを置く

色々すっ飛ばしてる気もしますが、一旦公式のサンプルをそのままコピペします。

Scaffold(
  body: CustomScrollView(
    slivers: <Widget>[
      SliverGrid(
        gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
          maxCrossAxisExtent: 200.0,
          mainAxisSpacing: 10.0,
          crossAxisSpacing: 10.0,
          childAspectRatio: 4.0,
        ),
        delegate: SliverChildBuilderDelegate(
          (BuildContext context, int index) {
            return Container(
              alignment: Alignment.center,
              color: Colors.teal[100 * (index % 9)],
              child: Text('grid item $index'),
            );
          },
          childCount: 20,
        ),
      ),
    ]
  )

image.png

画面ができました。

1行解説

このままでは解説になってないので使ってるプロパティを雑に訳してみます。

  • gridDelegate
    • グリッドのサイズ自体をコントロールするウィジェット。縦横のサイズとか余白とかを管理する。
  • delegate

    • 実際のグリッドの中に入るコンテンツを生成するウィジェットが入る。
  • SliverChildBuilderDelegate

    • ビルダーのコールバックを使うsliverに子ウィジェットを提供することを責務にしたクラス。
    • コンストラクタにbuilderを取る。
    • sliverは全部lazy constructなので、画面に出てないwidgetは表示されるまでconstructが遅延される。この辺のややこしい処理をSliverChildBuilderDelegateから生成されたbuilderが行ってくれる。
    • 逆に言うと、画面から見えなくなったウィジェットはdestoryされる(はずな)ので、もし画面外のに出たウィジェットを生かしたままにしたいのであればaddAutomaticKeepAlives: trueにする。

表示したい画像のリストを用意する

適当な画像のURLを拾ってきてリストにします。

_createSampleURLs() {
  final _urls = [];
  const _url =
    'https://kumamoto.photo/archives/_data/i/upload/2016/05/11/20160511090903-1c096f51-cu_e286.jpg';
  for (var i = 0; i < 20; i++) {
    _urls.add(_url);
  }
  return _urls;
}

final designURLs = _createSampleURLs();

出したいコンテンツの数を入れる

SliverChildBuilderDelegate.childCountに.lengthした数を入れます。ビルドされるタイルの数を制御します。

final designURLs = _createSampleURLs();

Scaffold(
  body: CustomScrollView(
    slivers: <Widget>[
      SliverGrid(
        gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
          maxCrossAxisExtent: 200.0,
          mainAxisSpacing: 10.0,
          crossAxisSpacing: 10.0,
          childAspectRatio: 4.0,
        ),
        delegate: SliverChildBuilderDelegate(
          (BuildContext context, int index) {
            return // todo

          },
          childCount: designURLs.length, 
        ),
      ),
    ]
  )

出したいコンテンツのbuilderを定義する

最後に、出したいコンテンツのbuilderを定義します。childの数だけbuilderに指定した関数が実行されてタイルが1つ1つビルドされます。具体的には以下のような感じです。

final designURLs = _createSampleURLs();

Scaffold(
  body: CustomScrollView(
    slivers: <Widget>[
      SliverGrid(
        gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
          maxCrossAxisExtent: 200.0,
          mainAxisSpacing: 10.0,
          crossAxisSpacing: 10.0,
          childAspectRatio: 4.0,
        ),
        delegate: SliverChildBuilderDelegate(
          (BuildContext context, int index) {
            return Container(
              child: Image(
                image: NetworkImage(designURLs[index]),
                fit: BoxFit.fitWidth,
              ),
            );
          },
          childCount: designURLs.length, 
        ),
      ),
    ]
  )

画面は以下のようになるはず。

image.png

公式のコピペでそのまま来ましたが、gridDelegateはいじってればだいたい分かると思うので割愛します。

まとめ

SliverGridで動的にグリッドを実装しました。落ち着いて見ればそんなに難しくないはずなので頑張りましょう。

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6