【Flutter】Containerのmarginの設定方法 – EdgeInsetsをざっくりまとめる

2022/10/28
2020/11/11

はじめに

Containerにmarginを設定する時、 EdgeInsets.only() で全て設定していませんか?

この記事では、Containerにmargin(外側の余白)/padding(内側の余白)を設定するいろいろな方法についてご紹介します。言い換えると、その設定に使用する EdgeInsets についてざっくりまとめていきます。

想定読者

  • Containerに余白を設定したいがわからない方
  • marginを設定する時、全て EdgeInsets.only() で設定してしまっている方

検証環境

  • macOS Catalina 10.15.7

$ flutter doctor
 
[] Flutter (Channel stable, 1.22.1, on Mac OS X 10.15.7 19H2, locale ja-JP)
[] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
[] Xcode - develop for iOS and macOS (Xcode 12.1)
[] Android Studio (version 3.5)
[] VS Code (version 1.50.1)

きほんのき – margin/paddingの設定方法

まずはmargin/paddingを設定する方法から説明します。(分かる人は飛ばしてください)

かなり基本になりますが、Containerを表示する際にmarginを設定すると、要素の外側に一定の余白をとることができます。

import 'package:flutter/material.dart';
 
void main() {
  runApp(MyApp());
}
 
class MyApp extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('PlayGround'),
        ),
        body: Container(
          margin: EdgeInsets.only(left: 100),
          color: Colors.redAccent,
          width: 100,
          height: 100,
        ),
      ),
    );
  }
}

margin: EdgeInsets.only(left: 100) とすることで、赤色の図形の左側に余白ができました。

同じ要領でpaddingを設定すると、図形の内部にも余白を指定することが可能です。

return Container(
  margin: EdgeInsets.only(top: 100),
  padding: EdgeInsets.only(top: 50),
  color: Colors.redAccent,
  width: 200,
  height: 100,
  child: Text('test'),
);

この例ではpaddingでContainerの内部に top:50 と設定しているため、Container内部のTextが下にずれて表示されています。

このような形で要素間に一定のスペースをとるためにmargin/paddingは頻繁に使用されます。

参考程度に、上記のスクリーンショットは僕自身が開発しているアプリの1画面ですが、この画面を構成している各要素もmargin/paddingが各所に設定されています。

次以降の章では、このmargin/paddingを設定する際に使用しているEdgeInsetsの様々な設定方法について説明していきます。

EdgeInsetsの様々な設定方法

EdgeInset.only()をひたすらに使っていっても問題はありませんが、EdgeInsetsにはもっと便利なメソッドがあります。

今回はその中でよく見かけるメソッドをピックアップしてご紹介します。

EdgeInsets.only()

/// Creates insets with only the given values non-zero.
///
/// {@tool snippet}
///
/// Left margin indent of 40 pixels:
///
/// ```dart
/// const EdgeInsets.only(left: 40.0)
/// ```
/// {@end-tool}
const EdgeInsets.only({
  this.left = 0.0,
  this.top = 0.0,
  this.right = 0.0,
  this.bottom = 0.0,
});

EdgeInsets.only() は引数を4つとることができ、上下左右の各方向へ自由に余白を設定することができます。

return Container(
  ,margin: EdgeInsets.only(top: 50, left: 100),,
  color: Colors.green,
  width: 100,
  height: 100,
);

EdgeInsets.only() を使うことで、left: 100, top:50 と各方向へ別々の値を設定することができます。

EdgeInsets.all()

/// Creates insets where all the offsets are `value`.
///
/// {@tool snippet}
///
/// Typical eight-pixel margin on all sides:
///
/// ```dart
/// const EdgeInsets.all(8.0)
/// ```
/// {@end-tool}
const EdgeInsets.all(double value)
  : left = value,
    top = value,
    right = value,
    bottom = value;

EdgeInsets.all() は only() と違い、引数を1つだけとって4方向全てに対して余白を設定することができます。

return Row(
  children: [
    Container(
      ,margin: EdgeInsets.all(50),,
      color: Colors.green,
      width: 100,
      height: 100,
    ),
    Container(
      color: Colors.red,
      width: 100,
      height: 100,
    ),
  ],
);

緑色のContainerの4方向にmarginが設定されているので、赤色のContainerにmarginを設定していなくとも全方向に余白を設定することができます。

EdgeInsets.symmetric()

/// Creates insets with symmetrical vertical and horizontal offsets.
///
/// {@tool snippet}
///
/// Eight pixel margin above and below, no horizontal margins:
///
/// ```dart
/// const EdgeInsets.symmetric(vertical: 8.0)
/// ```
/// {@end-tool}
const EdgeInsets.symmetric({
  double vertical = 0.0,
  double horizontal = 0.0,
}) : left = horizontal,
     top = vertical,
     right = horizontal,
     bottom = vertical;

EdgeInsets.symmetric() は引数を2つとることができ、縦方向、横方向それぞれの方向へ余白を設定することができます。

return Column(
  children: List.generate(
    5,
    (index) => Card(
      color: Colors.white10,
      ,margin: EdgeInsets.symmetric(
        vertical: 10.0,
        horizontal: 20.0,
      ),,
      child: Container(height: 100),
    ),
  ),
);

vertical: 10.0 で上下方向に10.0ずつ余白を設定しています。これは EdgeInsets.only(top: 10.0, bottom: 10.0) と同義です。

もう1つの引数 horizontal: 20.0 で左右方向に20.0ずつ余白を設定しています。これは EdgeInsets.only(left: 20.0, right: 20.0) と同義です。

EdgeInsets.only() で上下(または左右)に同じ値を設定する場合は、こちらを使う方が可読性含めてよいと思います。

EdgeInsets.fromLTRB()

/// Creates insets from offsets from the left, top, right, and bottom.
const EdgeInsets.fromLTRB(this.left, this.top, this.right, this.bottom);

EdgeInsets.fromLTRB() は引数を4つとり、各方向への余白を設定できます。

EdgeInsets.only() と違う点は、名前なし引数であること、余白0の場合も明示的に引数を指定しなければいけない点です。

return Column(
  children: List.generate(
    5,
    (index) => Card(
      color: Colors.redAccent,
      ,margin: EdgeInsets.fromLTRB(0.0, 20.0, 30.0, 5.0),,
      child: Container(height: 100),
    ),
  ),
);

各方向へ自由に余白を設定できます。

個人的にはこのような場合は EdgeInsets.only() を使う方がよいと思うので利用シーンが思いつかないです。。

その他Tips

この記事を参考にしてくれるレベル感の読者に向けて、知っておくと便利なTipsを書いておきます。

EdgeInsetsの加減算ができる

なんとEdgeInsetsは加減算することができます。

EdgeInsets verticalMargin = EdgeInsets.symmetric(vertical: 10.0);
EdgeInsets sideMargin = EdgeInsets.symmetric(horizontal: 20.0);
 
return Column(
  children: List.generate(
    5,
    (index) => Card(
      color: Colors.orangeAccent,
      margin: verticalMargin + sideMargin,
      child: Container(height: 100),
    ),
  ),
);

「左右のmarginだけは固定で決まっている」みたいなユースケースでは、変数として EdgeInsets.symmetric を定義しておいて、その変数+上下のmarginを自由に設定する みたいな使い方ができそうですね。

エディタ上で仕様を確認できる

Flutterの開発をしている方はAndroid StudioかVSCodeを使用していると思うのですが、エディタでEdgeInsetsの仕様を確認することができます。

クラスやメソッドなどを ⌘+クリック すると、その宣言にジャンプすることができるのですが、Flutter側で実装されているEdgeInsetsなども同様にジャンプすることができます。

<span class="font-semibold">↑ Android StudioでEdgeInsetsの仕様を確認できる</span>

↑ Android StudioでEdgeInsetsの仕様を確認できる

<span class="font-semibold">↑ VSCodeでEdgeInsetsの仕様を確認できる</span>

↑ VSCodeでEdgeInsetsの仕様を確認できる

実装に困った時や初めてのWidgetを扱う時は、一度宣言に飛ぶことで仕様を確認することをオススメします。

今回ご紹介したものは全てEdgeInsetsの宣言に飛ぶことで理解できる内容なので、日頃から扱うWidgetの仕様を確認すると理解が捗ると思います。

constで定義してパフォーマンスを改善する

若干EdgeInsetsの話からは逸れてしまいますが、marginの幅が固定なのであれば const修飾子をつける クセをつけておくとよいです。

メリットとしては、ユーザーのアクションによってデータが変更される時にアプリが自動で表示されているWidgetを再構成して見た目を更新してくれるのですが、その 描画のパフォーマンスを改善 することができます(劇的な改善にはなりません)

Flutterの初期プロジェクトでも、FABをタップすることでsetState()を呼び出してcountを+1し、それに応じてbuildメソッドが再度呼び出されてカウント数が更新されます(かなり雑に例をあげました)

const修飾子 をつけてあげることで、Widgetの再描画の対象から外されるのでパフォーマンスの改善につなげることができます。

return Column(
  children: List.generate(
    5,
    (index) => Card(
      color: Colors.redAccent,
      margin: const EdgeInsets.fromLTRB(0.0, 20.0, 30.0, 5.0),
      child: Container(height: 100),
    ),
  ),
);

EdgeInsetsの引数が固定の場合は問答無用で const をつけてあげましょう。(他のWidgetにも言えることなので気になる方は調べてください)

まとめ

この記事では、marginの基本的な設定の仕方からEdgeInsetsのいろいろな使い方をご紹介しました。

知識0の状態から学んでいる人にとっては、とりあえず EdgeInsets.only() で動いてしまうのでそのままにしがちな内容だと思います。そういう方の学びになればと思います。

Flutter の記事