Dart

8. FlutterのGridViewレイアウトを学習する

本日はFlutter のGridViewについて学習します。

前回は複数のウィジェットを乗せるためのウィジェットColumnとRowについて学びました。ColumnはiOSでいえばUITableView、AndroidではRecyclerViewと同じような役割を持っていました。
本日のGridViewはどちらかというとiOSでいえばUICollectionViewみたいに使えるウィジェットになります。

ちょうどインスタグラムみたいなレイアウトが作れるウィジェットというイメージですね。

f:id:qed805:20200126150934p:plain

instagramの写真投稿画面

グーグルの画像検索から引っ張ってきました。
赤枠のところが該当の部分です。

GridViewについて

さて、GridViewには2種類のレイアウトが存在します。
GridView.countとGridView.extendというウィジェットです。

Flutter iOS
GridView.count 横列に並べるitem を個数で制御する(個数指定)
GridView.extend 横列に並べるitem をサイズで制御する(サイズ指定)

このようなイメージです。

試しにサンプルコードを書いてみます。

collectionview.dart

import 'package:flutter/material.dart';

class CollectionView extends StatefulWidget {
  @override
  _CollectionViewState createState() => _CollectionViewState();
}

class _CollectionViewState extends State<CollectionView> {
  var _viewData = <Widget>[
    Container(
      color: Colors.red,
      child:
      Text(
        "1",
        style: TextStyle(
            fontSize: 32.0, fontWeight: FontWeight.w400, fontFamily: "Roboto"),
      ),
    ),
    Container(
      color: Colors.blue,
      child:
      Text(
        "2",
        style: TextStyle(
            fontSize: 32.0, fontWeight: FontWeight.w400, fontFamily: "Roboto"),
      ),
    ),
    Container(
      color: Colors.green,
      child:
      Text(
        "3",
        style: TextStyle(
            fontSize: 32.0, fontWeight: FontWeight.w400, fontFamily: "Roboto"),
      ),
    ),
    Container(
      color: Colors.yellow,
      child:
      Text(
        "4",
        style: TextStyle(
            fontSize: 32.0, fontWeight: FontWeight.w400, fontFamily: "Roboto"),
      ),
    ),
    Container(
      color: Colors.pink,
      child:
      Text(
        "5",
        style: TextStyle(
            fontSize: 32.0, fontWeight: FontWeight.w400, fontFamily: "Roboto"),
      ),
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('App Name'),
      ),
      body: GridView.count(
          crossAxisCount: 2,
          mainAxisSpacing: 10.0,
          crossAxisSpacing: 10.0,
          padding: EdgeInsets.all(10),
          children: _viewData),
    );
  }
}

main.dart

import 'package:flutter/material.dart';
import './collectionview.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  final title = 'GridViewのサンプルコード';
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      debugShowCheckedModeBanner: true,
      title: 'GridView App',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
        primaryColor: const Color(0xff2196f3),
        accentColor: const Color(0xff2196f3),
        canvasColor: const Color(0xfffafafa),
      ),
      home: new CollectionView(),
    );
  }
}

横は2列に設定しました。ビルドすると下記のような画面が表示されます。

f:id:qed805:20200126153705p:plain

GridView

GridViewの基本形は次のようになります。

GridView.count(
          crossAxisCount: [個数],
          mainAxisSpacing: [スペース],
          crossAxisSpacing: [スペース],
          padding: EdgeInsets.all(10),
          children: _viewData)

crossAxisCountプロパティが横にいくつ並べるかを制御するものになります。

crossAxisCountを3に設定すると横に3つ並ぶレイアウトになります。

f:id:qed805:20200126153726p:plain

横に3つのレイアウトが並ぶデザイン

このようにcrossAxisCountを変更するとRowの制御のようにできてしまうのがGridView.countのメリットかと思います。

それに対してGridView.extend はサイズを指定することで横に並べるレイアウトの個数を調整できるウィジェットです。

GridView.extent(maxCrossAxisExtent: 200,
      mainAxisSpacing: 10.0,
      crossAxisSpacing: 10.0,
      padding: EdgeInsets.all(10.0),
      children: _viewData)

さきほどのcollectionview.dartを次のように変更します。

GridViewの生成のところだけ変更しています。
また、main.dartは上記と同じものを使用しています(つまり変更なしです)

collectionview.dart

import 'package:flutter/material.dart';

class CollectionView extends StatefulWidget {
  @override
  _CollectionViewState createState() => _CollectionViewState();
}

class _CollectionViewState extends State<CollectionView> {
  var _viewData = <Widget>[
    Container(
      color: Colors.red,
      child:
      Text(
        "1",
        style: TextStyle(
            fontSize: 32.0, fontWeight: FontWeight.w400, fontFamily: "Roboto"),
      ),
    ),
    Container(
      color: Colors.blue,
      child:
      Text(
        "2",
        style: TextStyle(
            fontSize: 32.0, fontWeight: FontWeight.w400, fontFamily: "Roboto"),
      ),
    ),
    Container(
      color: Colors.green,
      child:
      Text(
        "3",
        style: TextStyle(
            fontSize: 32.0, fontWeight: FontWeight.w400, fontFamily: "Roboto"),
      ),
    ),
    Container(
      color: Colors.yellow,
      child:
      Text(
        "4",
        style: TextStyle(
            fontSize: 32.0, fontWeight: FontWeight.w400, fontFamily: "Roboto"),
      ),
    ),
    Container(
      color: Colors.pink,
      child:
      Text(
        "5",
        style: TextStyle(
            fontSize: 32.0, fontWeight: FontWeight.w400, fontFamily: "Roboto"),
      ),
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('App Name'),
      ),
      body: GridView.extent(maxCrossAxisExtent: 100,
      mainAxisSpacing: 10.0,
      crossAxisSpacing: 10.0,
      padding: EdgeInsets.all(10.0),
      children: _viewData)
    );
  }
}

これをビルドすると下記のように表示されます。

f:id:qed805:20200126154648p:plain

iPhoneXでの見え方

GridView.countもGridView.extendも同じように見えますが、端末が縦向きだけでなく横向きにもなる場合に大きな違いが見えます。
なので、iOSでいえばAutoLayoutなので端末の回転にも対応させたい時に検討するのだろうと思います。

本日は以上になります。

ABOUT ME
tamappe
都内で働くiOSアプリエンジニアのTamappeです。 当ブログではモバイルアプリの開発手法について紹介しています。メインはiOS、サブでFlutter, Android も対応できます。 執筆・講演のご相談は tamapppe@gmail.com までお問い合わせください。