【Flutter】Container の使い方完全ガイド|間違えやすいポイントと最適な活用方法を解説!

プロフィール画像

柴田晃清

2025年02月27日

リンクをコピーXでシェアするfacebookでシェアする

はじめに 

株式会社メンバーズ Cross ApplicationOpen in new tab カンパニーの柴田です。

Flutterアプリ開発において、Containerは非常に便利なWidgetですが、使い方を誤るとパフォーマンスや可読性に悪影響を及ぼすことがあります。特に、無駄なリビルドを引き起こすような使い方や、代替可能なWidgetを使わずにContainerを選んでしまい意図が見えづらいコードになってしまっている例がよく見られます。本記事では、Containerの実装とそこからわかる利用時のアンチパターンを2つ紹介し、その対処方法について詳しく解説します。

Containerの内部構造と仕組みを解説

Flutter SDKのWidgetの実装を読むのはハードルが高そうに感じますが、Containerクラスは、普段開発者もよく使用するStatelessWidgetを継承しているため実は非常に簡単です。
簡略化したContainerのコードを次に示します。

class Container extends StatelessWidget {
  Container({
    this.child,
    this.color,
    // ...
  });

  final Widget? child;
  final Color? color;
  // ...

  @override
  Widget build(BuildContext context) {
    Widget? current = child;

    // ...
    if (color != null) {
      current = ColoredBox(color: color!, child: current);
    }
    // ...

    return current!;
  }
}

Containerのbuild()メソッドを確認すると、Widget型の current という変数を加工し、最終的に適切なWidgetをreturnしていることがわかります。

Containerに特定の引数を指定すると、currentに適切なWidgetがラップされます。この簡略化したコードでは「if (color != null) 」の部分が該当します。実際には他の引数において似たような処理がなされています。例えばpaddingを引数に渡せばPadding Widgetが、alignmentを渡せばAlign Widgetがラップされていきます。

この実装から分かることは、Containerは複数Widgetをラップするときにシンプルにかけるという点で、有用なWidgetであるということです。裏を返すと、複数Widgetをラップしない場合にContainerを使っても旨みがないと言えます。

Container利用時のアンチパターン

Container利用時のアンチパターンを2つ挙げます。どちらもconstを使用することでrebuild回数を減らし、パフォーマンスを向上させることが可能です。また、Containerという抽象的な名前のWidgetではなく、より具体的な名前のWidgetを利用することでコードの意図を明確にすることを目指した提案です。

  • アンチパターン1: 引数が1つも無い時でもContainerを利用してしまう
// bad
Container();

// good
const SizedBox();

constにすることができるためSizedBox()を利用することをお勧めします。実際にはそんなに計算量はないため、あまり問題になりませんが、簡単に省ける無駄は省いた方が良いですね。

  • アンチパターン2: 代替可能なWidgetがある時にもかかわらずContainerを利用してしまう
// bad
Container(
  padding: const EdgeInsets.all(8.0),
  child: const Icon(Icons.question_mark),
);

// good
const Padding(
  padding: const EdgeInsets.all(8.0),
  child: const Icon(Icons.question_mark),
);

Containerにおいて、child以外の引数が1つの時には別のWidgetに置き換え可能な場合があります。以下の表は、Containerのchild以外の引数がある1つの引数の場合に代替を検討すべきWidgetの対応を表しています。ただしwidthとheightは同時に使用してもSizedBox()に代替可能です。全てがそのまま代替可能という訳ではないので実装しながら調整してください。このようにすることで、constをつけてrebuild範囲を限定できたり、Widgetの意図を伝えることが容易になります。

Containerの引数

代替を検討すべきWidget

alignment

Align()

padding

Padding()

color

ColoredBox()

decoration

DecoratedBox()

width

SizedBox()

height

SizedBox()

constraints

ConstrainedBox()

margin

Padding()

transform

Transform()

clipBehavior

ClipPath()

linterには、この問題を防ぐためのルールがいくつか存在します。これらを設定することも推奨します。

まとめ

本記事では、普段何気なく使っているContainerについて深掘りしました。Containerは、レイアウトやデザインにおいて非常に便利で柔軟な要素ですが、その使い方にはいくつかの最適な方法があります。本記事を参考に可読性とパフォーマンスを改善していきましょう!

この記事を書いた人

柴田晃清
柴田晃清
2021年メンバーズに入社。現在Cross Applicationカンパニーに所属。FlutterとAWSが好き。
ページトップへ戻る