実践Flutter

Flutterでスマホを中心にアプリ制作していきます。

Flutterアプリのレイアウトの基礎・RowとColumn

はじめに

今回はレイアウト系の最頻出ウィジェット、RowとColumnのポイントについて述べていきます。

Rowがウィジェット要素を横に並べるもの、Columnがウィジェット要素を縦に並べるものです。これを組み合わせて、縦に何分割、そのそれぞれを横に何分割、そのさらに奥を縦に何分割、という様に区切っていくことで画面全体のレイアウトを構成します。

例えば下の図では赤枠がColumun、青枠がRowです。最初に画面を縦にColumnで4分割、そして2番目と4番目の要素をそれぞれRowで4と2分割にしている例です:

f:id:linkedsort:20211108194245p:plain

RowとColumnは横と縦、以外の違いがありませんので、本文では基本的にRowを使ってサンプルを書いていきます。





Rowウィジェット

Rowは要素を横に並べるウィジェットです。横に並べるにしても様々な並べ方がありますので、これを中心に見ていきたいと思います。

まずはベースになるコードを作っていきます。

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    //(1) ルートのウィジェット
    return Directionality(
        textDirection: TextDirection.ltr,
        //(2) Columnを1回挟んでいます
        child: Column(
          children:[
            //(3) グレーの背景の四角を表示
            Container(
              height: 120,
              width: 1000,
              color: const Color.fromARGB(0xFF, 0xF0, 0xF0, 0xF0),
              //(4) ここからRowスタート
              child:Row(
                  children: [
                    Container(
                      color: Colors.amber,
                      height: 100,
                      width: 100,
                    ),
                    Container(
                      color: Colors.blueGrey,
                      height: 100,
                      width: 100,
                    ),
                    Container(
                      color: Colors.deepOrange,
                      height: 100,
                      width: 100,
                    )
                  ]
              )
          )]
        )
    );
  }
}

これを実行した結果は以下になります:

f:id:linkedsort:20211016124541p:plain

コードのポイント

(1) ルートのウィジェット

今回も前回までと同様、基盤にするWidgetをDirectionalityにしています。ここはMaterialAppなどでもOKです。

(2) Columnを1回挟んでいます

一回Columnを挟んで、その中でContainerで背景の薄いグレーの箱を描画しています。

Columnを入れているのは、これがないと薄いグレーを描画するContainerに「なるべく広がろうとする」作用が働いて画面いっぱいがグレーになってしまうためです。Columnを挟むことで、その子ウィジェットのContainerは指定したサイズ通りの表示になります。

(3) グレーの背景の四角を表示

高さ120、幅1000のグレーの四角をContainerで描画しています。

(4) ここからRowスタート


今回の主題のRowウィジェットです。children属性に色の違うContainerを3つ並べています。次節で述べるmainAxisAlignmentの値をここでは何も指定していないので、Rowウィジェットのchildrenの各要素は左から詰めて表示されています。


各種並べ方

ウィジェトの並べ方はmainAxisAlignment属性を与えることで指定することができます。各値の意味は以下です:

mainAxisAlignment値 ウィジェットの並び
MainAxisAlignment.center 中央寄せ
MainAxisAlignment.start 左寄せ。デフォルトはこれ
MainAxisAlignment.end 右寄せ
MainAxisAlignment.spaceAround 各要素の周囲に均等なスペースを確保
MainAxisAlignment.spaceBetween 両端を端に配置した上で要素間を均等配置
MainAxisAlignment.spaceEvenly 両端を含めて要素間を均等配置


下記はmainAxisAlignmentをMainAxisAlignment.centerにした場合です。サンプルコードのうちRowの部分だけを示します:

              child:Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Container(
                    color: Colors.amber,
                    height: 100,
                    width: 100,
                  ),
                  Container(
                    color: Colors.blueGrey,
                    height: 100,
                    width: 100,
                  ),
                  Container(
                    color: Colors.deepOrange,
                    height: 100,
                    width: 100,
                  )
                ]
              )

これを実行した結果は以下になります:

f:id:linkedsort:20211016130524p:plain

mainAxisAlignmentをMainAxisAlignment.startにした場合:

f:id:linkedsort:20211016124541p:plain

mainAxisAlignmentをMainAxisAlignment.endにした場合:

f:id:linkedsort:20211016130858p:plain

mainAxisAlignmentをMainAxisAlignment.spaceAroundにした場合:

f:id:linkedsort:20211016130943p:plain

mainAxisAlignmentをMainAxisAlignment.spaceBetweenにした場合:

f:id:linkedsort:20211016131017p:plain

mainAxisAlignmentをMainAxisAlignment.spaceEvenlyにした場合:

f:id:linkedsort:20211016131121p:plain

Columnウィジェットの場合はRowの表示を丁度全部縦にしたものになります。

おわりに

RowとColumnとContainerで自在にGUIを配置していくには、基本的に最初にスケッチを書いて、そこからどうやって分割するかを考えていけばOKです。

ここでの例題のように、実際のアイコンやボタンを置く前にContainerで四角く塗りつぶす形でまずはレイアウトを決めていってもよいかもしれません。よっぽど自由気ままなレイアウトでなければだいたいは縦横の区切りを組み合わせて表現できると思います。


f:id:linkedsort:20211108222506j:plain