2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Flutterのレイアウト入門【前編】Widget配置の基本とコツ

2
Last updated at Posted at 2026-02-05

モバイルアプリ開発エンジニアの木村です。
私が所属するエフアンドエムネット株式会社では、見積書アプリ検索ランキング1位の見積・請求書作成アプリ『ジムー』をはじめとするモバイルアプリ開発を行っており、私は主にアプリの開発を担当しています。

本記事では、私がFlutterで画面レイアウトをコーディングする際に、どのような手順で考えているかを共有します。 この記事は、Flutterをこれから始めてみたい方や、触り始めたばかりの初心者の方を対象としています。

はじめに

まずは、作成したい画面のレイアウトを確認してみましょう。 その際に、どのようなパーツが、どのような位置に配置されているのか、そしてどのように動くのかも合わせて確認するとコーディングが進めやすくなります。

今回は例として以下のようなログイン画面を見ていきます。
本記事ではこのログイン画面のパーツ配置(レイアウト)を解説していきます。
(後半の記事でテキストやボタンの設定を解説します。)
完成イメージのログイン画面

レイアウトのコーディング

前章で確認したログイン画面のレイアウトを、いくつかの手順に分けて実際にコーディングしていきます。

手順1:画面全体の余白を設定する

初めに、画面全体を確認して、パーツが配置されない上下左右の余白を確認しましょう。
以下の図のように、画面の端には余白(マージン)が設定されています。
ログイン画面の余白(マージン)を示した図
まずは、この余白から設定していきます。
余白を設定するには、Container というWidgetを使用します。body の子要素として Container を追加し、margin プロパティで余白を指定しましょう。

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        margin: const EdgeInsets.only(left: 30, top: 100, right: 30, bottom: 50),
      ),
    );
  }

手順2:各パーツの並び方(縦・横)を設定する

次に、各パーツがどの方向(縦または横)に並んでいるかを確認します。
今回の画面では、全てのパーツが縦方向に並んでいることが分かります。
Flutterでパーツを縦に並べるには Column というWidgetを使用します。先ほど追加した Container の子要素として Column を追加しましょう。

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        margin: const EdgeInsets.only(left: 30, top: 100, right: 30, bottom: 50),
        child: Column(
        ),
      ),
    );
  }

手順3:パーツの揃え方(左右・中央)を設定する

ログイン画面全体を見ると、多くのパーツは左端から配置されています。
そこで、手順2で追加した Column に、子要素を左寄せにする設定を追加しましょう。

左寄せにするには、crossAxisAlignment プロパティに CrossAxisAlignment.start を指定します。

Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        margin: const EdgeInsets.only(left: 30, top: 100, right: 30, bottom: 50),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
        ),
      ),
    );
  }

【補足】 Column(縦並び)の場合、crossAxisAlignment は水平方向(左右)の揃え方を指定します。mainAxisAlignment は垂直方向(上下)の揃え方を指定します。

手順4:画面にパーツを追加する

ログイン画面全体を見ると、大きく分けて8個のパーツが並んでいるのがわかります。
(ログインタイトル、ID入力欄、ログインボタンなど)

まずはレイアウトの骨組みを作るため、これらのパーツの代わりに仮の Container を8個配置してみましょう。 Column の children プロパティに 8個の Container を追加します。
(今回は分かりやすいように、仮のサイズ・色・余白を設定しています)

@override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        margin: const EdgeInsets.only(left: 30, top: 100, right: 30, bottom: 50),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            Container(
              margin: const EdgeInsets.all(5),
              height: 50,
              width: 200,
              color: Colors.orangeAccent,
            ),
            ///    省略      ///
            Container(
              margin: const EdgeInsets.all(5),
              height: 50,
              width: 200,
              color: Colors.orangeAccent,
            ),
          ],
        ),
      ),
    );
  }
仮のContainerを8個配置した画面

手順5:特定のパーツの揃え方(左右・中央)を設定する

手順3では全体を左寄せにしましたが、完成イメージを見ると「ログイン」というタイトルだけは画面の中央に表示されています。

このように、特定のパーツだけ表示位置を変更したい場合は、そのWidgetを Row Widgetで囲みます。
そして、Row の mainAxisAlignment プロパティに MainAxisAlignment.center を設定することで、その中のパーツを中央に寄せることができます。

///   省略   ///
child: Column(
  crossAxisAlignment: CrossAxisAlignment.start,
  children: [
    Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Container(
          margin: const EdgeInsets.all(5),
          height: 50,
          width: 200,
          color: Colors.orangeAccent,
        ),
      ],
    ),
///   省略   ///
タイトル部分を中央寄せにした画面

手順6:各パーツのサイズと余白を調整する

最後に、各パーツのサイズと、パーツ間の余白を調整して、完成イメージのレイアウトに近づけていきます。

各パーツのサイズは width と height で調整します。
入力欄やボタンのように、横幅いっぱいに表示したい場合は width に double.infinity を設定します。

パーツ間の余白は、Container の margin でも設定できますが、今回はパーツ間のスペースを明確にするため SizedBox を使います。

すべての手順を進めてきた、現時点でのソースコードと表示レイアウトは以下の通りです。

Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        margin: const EdgeInsets.only(left: 30, top: 100, right: 30, bottom: 50),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Container(
                  margin: const EdgeInsets.all(5),
                  height: 50,
                  width: 200,
                  color: Colors.orangeAccent,
                ),
              ],
            ),
            const SizedBox(
              height: 40,
            ),
            Container(
              margin: const EdgeInsets.all(5),
              height: 40,
              width: 200,
              color: Colors.orangeAccent,
            ),
            Container(
              margin: const EdgeInsets.all(5),
              height: 50,
              width: double.infinity,
              color: Colors.orangeAccent,
            ),
            const SizedBox(
              height: 20,
            ),
            Container(
              margin: const EdgeInsets.all(5),
              height: 40,
              width: 200,
              color: Colors.orangeAccent,
            ),
            Container(
              margin: const EdgeInsets.all(5),
              height: 50,
              width: double.infinity,
              color: Colors.orangeAccent,
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.end,
              children: [
                Container(
                  margin: const EdgeInsets.all(5),
                  height: 30,
                  width: 200,
                  color: Colors.orangeAccent,
                ),
              ],
            ),
            const SizedBox(
              height: 40,
            ),
            Container(
              margin: const EdgeInsets.all(5),
              height: 50,
              width: double.infinity,
              color: Colors.orangeAccent,
            ),
            Container(
              margin: const EdgeInsets.all(5),
              height: 50,
              width: double.infinity,
              color: Colors.orangeAccent,
            ),
          ],
        ),
      ),
    );
  }
完成イメージと作成中の画面の比較

まとめ

これでログイン画面のレイアウトの大枠は完成しました!

仮のオレンジ色の枠を、表示したい位置にそれぞれ設置することができましたね。
後編の記事では、このオレンジ色の枠を、それぞれテキスト、入力欄、ボタンに置き換えて、ログイン画面を完成させていきます。

Flutterのレイアウト入門【後編】主要Widgetで画面を完成させる方法

エフアンドエムネット株式会社からのお知らせ

最後までお読みいただきありがとうございます!
私たちエフアンドエムネット株式会社では、一緒に開発を楽しんでくれる仲間を募集しています。

ご興味を持っていただけましたら、ぜひ採用ページを覗いてみてください!

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?