初めに
Flutterで比率によるレイアウトをするにあたって躓いた部分を記事にしたいと思います。
今回は、Column
Row
のプロパティでレイアウトする方法と、Flexible
Widget系のflex
を指定してレイアウトする方法をご紹介します。
そんなの余裕だよ!って方は、飛ばして実践編に取り組んでみてください!
Tips
レイアウトを考えるときには、Dart DevTools の Flutter inspector が超便利です!
Tree構造や、余白、Widgetの範囲まで可視化してくれます!
Android Studio |
---|
![]() |
Visual Studio Code |
---|
![]() |
以下で画面に青線や、黄色線が表示されていますが、Flutter Inspectorによるものです。
不具合により、Flutter Inspectorを使えなかったり、上記のステップを飛ばした方はご注意ください。
今回は、比率をわかりやすくしたいので、Row
ではなくColumn
でサンプルを作っていきます。(この記事で伝えたいことは、Row
にもそのまま適用できます)
全てのColumn
はCenter
で囲っています。
復習編
初めは、シンプルにColumnで囲う
当たり前ですが、上から順番に詰めていますね。

mainAxisAlignmentプロパティを指定
childrenの要素数に応じて、Widget間の余白を計算してくれます!
spaceAround | spaceBetween | spaceEvenly |
---|---|---|
![]() |
![]() |
![]() |
Expandedで囲う
Expandedは、子要素を描画領域の最大サイズまで引き伸ばす、もしくは縮小させる Widget です。
ただし、Expanded
で囲っただけでは、Buttonのタップ可能範囲も引き伸ばされてしまうので、Center
で囲ってあげましょう。
これで、Column
にmainAxisAlignment.spaceAround
を指定した場合と同じレイアウトになりましたね。
Expanded -> child | Expanded -> Center -> child |
---|---|
![]() |
![]() |
実践編
それでは、以下の仕様を満たしてレイアウトしてみましょう!
-
Icon(Icons.flutter_dash_outlined)
とText
の間は、50 logical pixel - アイコンのサイズは100
-
Icon(Icons.flutter_dash_outlined)
とText
を合わせた矩形(以下矩形Widget
)の垂直中央は画面の中央と同じ -
Text
とIcon(Icons.sentiment_satisfied)
の間は、100 logical pixel

ヒント
SpacerとExpanded
を組み合わせてみよう!
解答例
class ColumnWithExpandedAndSpacer extends StatelessWidget {
const ColumnWithExpandedAndSpacer({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
const Spacer(
// 1の場合は省略可能
flex: 1,
),
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Icon(
Icons.flutter_dash_outlined,
size: 100,
),
SizedBox(
height: 50,
),
Text('I love Flutter'),
],
),
),
Expanded(
// 1の場合は省略可能
flex: 1,
child: Column(
children: [
const SizedBox(
height: 100,
),
Center(
child: IconButton(
onPressed: () {
print('Tapped satisfied');
},
icon: const Icon(Icons.sentiment_satisfied),
),
),
],
),
),
],
);
}
}
考え方
矩形Widget
を中心に設置する ということを意識すぎると沼にハマってしまうかもしれません。実際に自分も詰まったことがあります。
少し見方を変えると、矩形Widget
の上下のスペースが同じであればよい と考えることができそうですね!
そこで登場するのが、Spacerです!Spacer
はExpanded
と同じように、空いているスペースを描画領域の最大サイズまで引き伸ばしてくれます。
両方、flex
というプロパティを保持しており、スペースの割合を指定することができます。
今回は明示的にflex:1
としていますが、デフォルトで1が指定されるので省略可能です。
正確にいうと、Expanded
が継承しているFlexible
でflexは設定されています。
Expanded
class Expanded extends Flexible {
/// Creates a widget that expands a child of a [Row], [Column], or [Flex]
/// so that the child fills the available space along the flex widget's
/// main axis.
const Expanded({
super.key,
super.flex,
required super.child,
}) : super(fit: FlexFit.tight);
}
class Flexible extends ParentDataWidget<FlexParentData> {
/// Creates a widget that controls how a child of a [Row], [Column], or [Flex]
/// flexes.
const Flexible({
super.key,
this.flex = 1,
this.fit = FlexFit.loose,
required super.child,
});
:
省略
:
}

試しにSpacer
のflexに2を指定してみましょう。
Column(
children: [
const Spacer(
// flex を指定!
flex: 2,
),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Icon(
Icons.flutter_dash_outlined,
size: 100,
),
SizedBox(
height: 50,
),
Text('I love Flutter'),
],
),
Expanded(child: child),
],
),

Spacer
: Expanded
= 2 : 1 になっていますね!!
最後に
今回は 比率によるレイアウトのサンプルをご紹介しました!
レスポンシブなデザインに対応するには、比率によるレイアウトを考えることは必須になってきます。
自分もまだまだ勉強中ですので、自由自在にデザインできるように皆さん一緒に頑張りましょう!
参考
Flutter: MainAxisAlignmentを理解する
Flexible と Expanded って何が違うんだっけ?