banner
jzman

jzman

Coding、思考、自觉。
github

FlutterシリーズのFlexレイアウト詳細解説

PS:長期にわたって続けることは難しいことです。

Flutter は Google が提供するクロスプラットフォーム UI フレームワークで、Android と iOS 上で高品質なアプリケーションを迅速に構築できます。主な特徴は、Flutter が迅速な開発能力、表現力豊かで柔軟な UI、そして優れたネイティブパフォーマンスを持っていることです。本記事では Flutter の Flex レイアウトについて紹介します。以下の内容です:

  1. Flex の基本
  2. Flex の一般的な設定
  3. Row と Column
  4. Expanded と Flexible
  5. Spacer
  6. まとめ

Flex の基本#

Flex レイアウト方式は、フロントエンドやミニプログラム開発で広く使用されています。以前に Flex レイアウトを学んでいれば、Flutter でも大差ありません。Flexible Box の図は以下の通りです:

image

この図の説明については、前のこの記事を参照してください:

Flex Widget は主軸の方向を設定できます。主軸の方向がわかれば、Row または Column を直接使用できます。Flex Widget はスクロールできません。スクロールが必要な場合は ListView を使用することを検討してください。Flex Widget の内容がその幅と高さを超えると、黄黒の警告ストライプが表示されます。水平方向の例で表示されるエラーメッセージは以下の通りです:

I/flutter (14749): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter (14749): The following assertion was thrown during layout:
I/flutter (14749): A RenderFlex overflowed by 440 pixels on the right.

エラーメッセージは以下の通りです:

image

Flex の一般的な設定#

Flex の一般的な属性は以下の通りです:

  1. direction
  2. mainAxisAlignment
  3. mainAxisSize
  4. crossAxisAlignment
  5. verticalDirection
  6. textBaseline

direction#

主軸の方向を設定します。設定可能な値は Axis.horizontal と Axis.vertical で、交差軸は主軸の方向に対して垂直です。

mainAxisAlignment:#

子 Widget を主軸方向に沿って配置する方法を設定します。デフォルトは MainAxisAlignment.start で、設定可能な方法は以下の通りです:

  • MainAxisAlignment.start:左揃え、デフォルト値;
  • MainAxisAlignment.end:右揃え;
  • MainAxisAlignment.center:中央揃え;
  • MainAxisAlignment.spaceBetween:両端揃え;
  • MainAxisAlignment.spaceAround:各 Widget の両側の間隔が等しく、画面の端との間隔は他の Widget の間隔の半分;
  • MainAxisAlignment.spaceEvenly:各 Widget を均等に分配し、画面の端との間隔が他の Widget の間隔と等しい。

比較効果は以下の通りです:

image

mainAxisSize#

主軸のサイズを設定します。デフォルトは MainAxisSize.max で、設定可能な値は以下の通りです:

  • MainAxisSize.max:主軸のサイズは親コンテナのサイズ;
  • MainAxisSize.min:主軸のサイズはその子 Widget のサイズの合計。

比較効果は以下の通りです:

image

mainAxisAlignment を spaceBetween に設定し、mainAxisSize を max に設定すると、全体の Row の幅に基づいて spaceBetween の方法で配置されます。mainAxisSize を min に設定すると、3 つの Container の幅の合計範囲内で spaceBetween の方法で配置されます。

crossAxisAlignment#

子 Widget を交差軸方向に沿って配置する方法を設定します。デフォルトは CrossAxisAlignment.center で、設定可能な方法は以下の通りです:

  • CrossAxisAlignment.start:交差軸の開始位置に揃える;
  • CrossAxisAlignment.end:交差軸の終了位置に揃える;
  • CrossAxisAlignment.center:中央揃え;
  • CrossAxisAlignment.stretch:交差軸全体を埋める;
  • CrossAxisAlignment.baseline:最初の行の文字基線に揃える。

比較効果は以下の通りです:

image

verticalDirection#

垂直方向の子 Widget の配置順序を設定します。デフォルトは VerticalDirection.down で、設定方法は以下の通りです:

  • VerticalDirection.down:start が上部、end が下部;
  • VerticalDirection.up:start が下部、end が上部。

比較効果は以下の通りです:

image

交差軸設定の CrossAxisAlignment.end に注意して、これに基づく垂直方向の変化を観察してください。

textBaseline#

文字の揃えの基線タイプを設定します。設定可能な値は以下の通りです:

  • TextBaseline.alphabetic:文字基線に揃える;
  • TextBaseline.ideographic:表意文字基線に揃える;

使用時に crossAxisAlignment を baseline に設定する場合、textBaseline 属性の値を設定する必要があります。使用方法は以下の通りです:

// textBaseline
class FlexSamplePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Flex Sample"),
        centerTitle: true,
      ),
      body: Row(
        children: <Widget>[
          Expanded(
              child: Row(
                children: <Widget>[
                  Text("躬",style: TextStyle(fontSize: 40,),),
                  Text("x",style: TextStyle(fontSize: 60,),),
                  Text("ing",style: TextStyle(fontSize: 16,),),
                  Text("之",style: TextStyle(fontSize: 16,),),
                ],
          )),
          Expanded(
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.baseline,
                textBaseline: TextBaseline.alphabetic,
                children: <Widget>[
                  Text("躬",style: TextStyle(fontSize: 40,),),
                  Text("x",style: TextStyle(fontSize: 60,),),
                  Text("ing",style: TextStyle(fontSize: 16,),),
                  Text("之",style: TextStyle(fontSize: 16, ),),
                ],
          )),
          Expanded(
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.baseline,
                textBaseline: TextBaseline.ideographic,
                children: <Widget>[
                  Text("躬",style: TextStyle(fontSize: 40, ),),
                  Text("x",style: TextStyle(fontSize: 60,),),
                  Text("ing",style: TextStyle(fontSize: 16,),),
                  Text("之",style: TextStyle(fontSize: 16,),),
                ],
              ))
        ],
      ),
    );
  }
}

textBaseline 属性を設定しない場合、TextBaseline.alphabetic および TextBaseline.ideographic を設定した場合の比較効果は以下の通りです:

image

両者は基線の意味において異なりますが、テストでは違いが見られませんでした。今後も観察を続け、知っている方はコメントで指摘してください。

Row と Column#

Row と Column はどちらも Flex を継承しています。Row の主軸の方向は水平方向で、Column の主軸の方向は垂直方向です。つまり、Flex の基本に基づいて主軸の方向を設定します。以下の通りです:

// Row
direction: Axis.horizontal,
/// Column
direction: Axis.vertical,

主軸の方向が確定している場合は、Row または Column を直接使用できます。使用方法は Flex と同じです。

Expanded と Flexible#

Flexible の fix 属性はデフォルトで FlexFit.loose ですが、Expanded は Flexible を継承し、その fix 属性は FlexFit.tight に指定されています。両者は fix 属性が異なるため異なります。Flexible の fit 属性を FlexFit.tight に設定すると、Flexible は Expanded と等価になります。設定可能な fit 属性は以下の通りです:

  • tight:利用可能なスペースを強制的に埋める;
  • loose:利用可能なスペースを強制的に埋めず、Widget 自身のサイズ。

比較効果は以下の通りです:

image

Expanded は Row、Column、Flex 内のコンポーネントが主軸の利用可能なスペースを埋めることを可能にします。複数の Widget が Expanded コンポーネントを使用している場合、Expanded の flex 属性を使用して主軸のスペースを比率で分配できます。flex 属性は Android の LinearLayout の weight 属性に相当します。以下の通りです:

// Expanded
class ExpandedSamplePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Row Sample"),
          centerTitle: true,
        ),
        body: Row(
          mainAxisAlignment: MainAxisAlignment.start,
          mainAxisSize: MainAxisSize.max,
          children: <Widget>[
            Expanded(
              flex: 1,
              child: Container(
                  width: 50,
                  height: 50,
                  color: Colors.red,
                  child: Center(
                    child: Text(
                      "A",
                      style: TextStyle(fontSize: 20, color: Colors.white),
                    ),
                  )),
            ),
            Expanded(
              flex: 2,
              child: Container(
                  width: 50, // Row Expanded下width無効
                  height: 50, // Column Expanded下height無効
                  color: Colors.green,
                  child: Center(
                    child: Text(
                      "B",
                      style: TextStyle(fontSize: 20, color: Colors.white),
                    ),
                  )),
            ),
            Container(
                width: 50,
                height: 50,
                color: Colors.yellow,
                child: Center(
                  child: Text(
                    "C",
                    style: TextStyle(fontSize: 20, color: Colors.white),
                  ),
                )),
          ],
        ));
  }
}

表示効果は以下の通りです:

image

Spacer#

Spacer は Widget 間の間隔を調整するために使用され、すべての残りのスペースを占有します。そのため、MainAxisAlignment の設定は無効になります。Spacer の属性 flex は残りのスペースの配分の重みを設定するために使用され、デフォルト値は 1 で、すべての残りのスペースを占有します。2 つ以上の Spacer がある場合は、flex に従って残りのスペースを配分します。コードは以下の通りです:

class RowSamplePage1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Row Sample"),
          centerTitle: true,
        ),
        body: ConstrainedBox(
          constraints: BoxConstraints(maxHeight: 150),
          child: Row(
            children: <Widget>[
              Container(
                width: 80,
                height: 80,
                color: Colors.red,
              ),
              Spacer(flex: 1,),
              Container(
                width: 80,
                height: 80,
                color: Colors.green,
              ),
              Spacer(flex: 2,),
              Container(
                width: 80,
                height: 80,
                color: Colors.yellow,
              ),
            ],
          ),
        ));
  }
}

表示効果は以下の通りです:

image

以上は Flutter における Flex レイアウトに関する内容を主に学びました。重点は Flex の基本概念を理解し、その上で Flex レイアウトを学び、検証することです。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。