行 Row
と Expanded
を使って、横並びで均等にかつレスポンシブに要素を並べてみます。
横方向に要素を並べる
Row
は横方向に要素を並べるための Widget です。
children
に並べたい要素を配列として要素を入れていきます。
このトピックでは、赤、青、緑の 3 個の Container
が入ってる Row
の例を使って解説を進めていきます。
Container を並べる
まずは Row
に 3 つの Container
を入れていきましょう。
MainAxisAlignment.spaceEvenly
は、子要素を横方向に均等に配置する設定です。(詳細はこちら)
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(color: Colors.red),
Container(color: Colors.blue),
Container(color: Colors.green),
],
)
実は、このように Container
の height
と width
を指定せずに書いたら、下の画面のように何も表示されません。

height
と width
を指定すれば、3 種類の Container
が表示されるようになります。
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
color: Colors.red,
height: 80, // サイズ指定しないと表示されない
width: 80,
),
Container(
color: Colors.blue,
height: 80,
width: 80,
),
Container(
color: Colors.green,
height: 80,
width: 80,
),
],
),

サイズをレスポンシブに表示する
ユーザーが使用するデバイスの画面サイズはそれぞれ異なるので、すべての画面サイズに対応したアプリを作るのに、 Expanded
は必要不可欠な存在です。
例えば、親 Widget の横幅がデバイスのサイズによって縮小された場合、前節のコードのままでアプリを起動すると、どうなるでしょうか。
答えは、以下のように親 Widget の右側に RenderFlex Overflowed
エラーが検出されます。
このエラーメッセージは、指定された子要素の横幅は親 Widget の横幅を越えていることを意味しています。

height = 80
のようにサイズをハードコーディングをすると、上記のようなエラーに遭遇するユーザーがいるかもしれません。それによって、ユーザーフレンドリーではないアプリと認識されて、ユーザー離れに繋がるので気をつけましょう。
異なるサイズのデバイスに対応するためには、 Expanded
を使いましょう。
Expanded
は、子要素のサイズを親 Widget のサイズに対してレスポンシブに変化させます。
使い方もとても簡単で、レスポンシブにしたい子要素を包むだけです。
例えば、赤の Container
を Expanded
で包み、
Row(
children: [
Expanded(
child: Container(
color: Colors.red,
height: 80,
width: 80, // 指定されても、Expanded に包まれると無視される
),
),
Container(
color: Colors.blue,
height: 80,
width: 80, // キープされる
),
Container(
color: Colors.green,
height: 80,
width: 80, // キープされる
),
],
),
のように書くと、どうなるでしょうか。
その結果は、赤の Container
の width
に設定された値が無視されて、赤の Container
は取れるだけの横幅を持つようになります。

青と緑の Container
は Expanded
に包まれてないので、それらの width
は 80 ピクセルのまま表示されます。
次に、残りの青と緑の Container
も Expanded
で包むと、3 つの Container
が均等に配置されるようになります。
Row(
children: [
Expanded(
child: Container(
color: Colors.red,
height: 80,
width: 80, // 指定されても、Expanded に包まれると無視される
),
),
Expanded(
child: Container(
color: Colors.blue,
height: 80,
width: 80, // 指定されても、Expanded に包まれると無視される
),
),
Expanded(
child: Container(
color: Colors.green,
height: 80,
width: 80, // 指定されても、Expanded に包まれると無視される
),
),
],
),

親 Widget である Row
の中に、左右の空白や子要素の間隔もレスポンシブに作ることができます。
Expanded
の child
を空の状態で起動するとエラーが出てしまいます。
そこで、小要素の child
が必要のない空の Expanded
、とも言える便利な Widget Spacer
を使うと、レスポンシブな空白を簡単に実装できます。
それでは、Spacer
を使ってレスポンシブな空白を入れていきましょう。
Row(
children: [
Spacer(), // レスポンシブな空白
Expanded(
child: Container(
color: Colors.red,
height: 80,
width: 80,
),
),
Spacer(), // レスポンシブな空白
Expanded(
child: Container(
color: Colors.blue,
height: 80,
width: 80,
),
),
Spacer(), // レスポンシブな空白
Expanded(
child: Container(
color: Colors.green,
height: 80,
width: 80,
),
),
Spacer(), // レスポンシブな空白
],
),

これで、親 Widget の幅が小さくなっても、子要素はそれに合わせてレスポンシブに変化するようになりました。
そして、以前に表示されていた RenderFlex Overflowed
エラーが解消されました。

Flex を使って子要素のサイズ配分を調節する
また、Expanded
と Spacer
に flex
というプロパティを追加すると、flexに指定する値分だけ、要素のサイズを確保してくれます。
flex: 3
と指定すると、要素3つ分のスペースを確保してくれます。
例えば、 赤、青、緑の Container
に、それぞれ flex: 1
、flex: 2
、flex: 3
を設定すると、
下の画像のように、3 つの Container
が横幅 1 : 2 : 3 で配分されるようになります。
Row(
children: [
Expanded(
flex: 1, // 1 要素分の横幅
child: Container(
color: Colors.red,
height: 80,
width: 80,
),
),
Expanded(
flex: 2, // 2 要素分の横幅
child: Container(
color: Colors.blue,
height: 80,
width: 80,
),
),
Expanded(
flex: 3, // 3 要素分の横幅
child: Container(
color: Colors.green,
height: 80,
width: 80,
),
),
],
),

今回は Row
での Expanded
の使い方を説明しました。
Column
においても、ほぼ同じ方法で使用できます。
ただし、Row
では width
がレスポンシブ対応されるのに対して、Column
では height
がレスポンシブ対応されます。