【Flutter】Expanded完全ガイド!使い方とコツ

対象者

  • Flutterを使ったアプリ開発を始めたばかりのエンジニアやプログラマー
  • アプリのレイアウト作成で、ウィジェットのスペース調整方法に悩んでいる方
  • 効率的なアプリ開発方法を学び、スキルアップを目指している方

はじめに

Flutter開発者の皆さん、RowやColumnを使ったレイアウトでスペース調整に悩んだことはありませんか?そんな時、強力な味方となるのが「Expanded」ウィジェットです。この記事では、Expandedウィジェットの使い方や活用法を徹底解説します。また、同じくFlexを継承した「Flexible」ウィジェットとの違いも明らかにし、それぞれの適切な使用シーンを理解していただけるようになります。

この記事を読むことで、あなたのFlutterアプリのレイアウトがより綺麗で効率的になり、開発のストレスが軽減されるでしょう。さあ、一緒にExpandedウィジェットを使いこなしましょう!

Flutter Expandedの基本

Expandedとは

Expandedは、RowやColumnなどの子ウィジェットのスペースを目一杯埋めるために使われるウィジェットです。Expandedを使用することで、縦や横にいっぱいに広がるレイアウトを実現できます。

Expandedの使い方

Expandedウィジェットを使用するには、RowやColumnの子ウィジェットとして配置します。例えば、次のようにExpandedを使用してTextウィジェットを画面いっぱいに表示できます。
Expanededを使用した時

Column(
    children: const [
      ColoredBox(color: Colors.green, child: Text('Expandedなし')),
      Expanded(
        child: ColoredBox(color: Colors.yellow, child: Text('Expandedあり')),
      ),
    ],
),

flexの使い方

FlutterのExpandedウィジェットは、RowやColumn内で子ウィジェット間のスペース調整に役立ちます。flexプロパティを使用することで、ウィジェット間のスペース配分を調整することができます。

Column(
  children: [
    Expanded(
      flex: 1,
      child: Container(
        color: Colors.red,
        child: Center(child: Text('Flex 1')),
      ),
    ),
    Expanded(
      flex: 2,
      child: Container(
        color: Colors.green,
        child: Center(child: Text('Flex 2')),
      ),
    ),
    Expanded(
      flex: 3,
      child: Container(
        color: Colors.blue,
        child: Center(child: Text('Flex 3')),
      ),
    ),
  ],
),

このサンプルコードでは、Column内に3つのExpandedウィジェットがあります。それぞれのflexプロパティに1, 2, 3と設定しています。flexの値が大きいほど、そのウィジェットは親ウィジェット内でより多くのスペースを占めることになります。この例では、赤・緑・青のコンテナがそれぞれ1:2:3の割合でスペースを占めています。

flexを使用しない場合、すべてのExpandedウィジェットが均等にスペースを占めることになります。上記でflexがなかった場合、3つのコンテナが1:1:1の割合でスペースを占めます。

Expandedの実践的な利用例

Expandedを用いたレイアウト調整

Expandedを使用して、コンテンツの間隔を調整したり、複数の子ウィジェットを均等に配置したりすることができます。以下は、Rowウィジェット内に3つのTextウィジェットを均等に配置する例です。

Row(
  children: <Widget>[
    Expanded(child: Text('左')),
    Expanded(child: Text('中央')),
    Expanded(child: Text('右')),
  ],
);

複数のExpandedウィジェットを組み合わせる

複数のExpandedウィジェットを組み合わせることで、より複雑なレイアウトを作成できます。以下は、Row内に2つのColumnを配置し、それぞれのColumn内にTextウィジェットを表示する例です。

Row(
  children: <Widget>[
    Expanded(
      child: Column(
        children: <Widget>[
          Text('左上'),
          Text('左下'),
        ],
      ),
    ),
    Expanded(
      child: Column(
        children: <Widget>[
          Text('右上'),
          Text('右下'),
        ],
      ),
    ),
  ],
);

Expandedのある・なしで広いスペースをとるWidgetを決める

この例で言うと、「広いスペース」のみExpandedをつけて、その他にはつけてません。
そのため、広いスペースを取りたいところを指定して、他の要素を左寄せと右寄せにすることができます。

Row(
    children: [
      Text('左寄せ'),
      Text('左寄せ'),
      Expanded(child: Text('広いスペース')),
      Text('右寄せ')
    ],
),

ExpandedとFlexibleの違いと使い分け

ExpandedとFlexibleは似た働きをしますが、違いがあります。Expandedは、子ウィジェットのスペースを最大限に広げることを優先します。
一方、Flexibleは、子ウィジェットのスペースをフレキシブルに調整できるように設計されています。Expandedは、Flexibleにfit: FlexFit.tightを設定したものと同じです。デフォルトは、FlexFit.looseです。

この例では、左から

  • 黒の固定の大きさのContainer(100×100)
  • 赤のFlexible:FlexFit.loose のContainer(50×50)
  • 緑のFlexible:FlexFit.tight のContainer(50×50)
  • 青のExpaneded のContainer(50×50)

青の右側に白い空白の部分があります。それは、赤い部分をExpandedしたときと現在のFlexFit.looseの幅の差分になってます。(その部分は、Expanededで埋めないんだなぁ、と)

 Row(
    children: [
      Container(color: Colors.black, width: 100, height: 100),
      Flexible(
        fit: FlexFit.loose,
        child: Container(
          color: Colors.red,
          height: 50,
          width: 50,
          child: Text('Flexible: FlexFit.loose'),
        ),
      ),
      Flexible(
        fit: FlexFit.tight,
        child: Container(
          color: Colors.green,
          height: 50,
          width: 50,
          child: Text('Flexible: FlexFit.tight'),
        ),
      ),
      Expanded(
        child: Container(
          color: Colors.blue,
          height: 50,
          width: 50,
          child: Text('Expanded'),
        ),
      ),
    ],
  ),

使い分け方としては、子ウィジェットのスペースを最大限に広げたい場合はExpandedを、子ウィジェットのスペースを柔軟に調整したい場合はFlexibleを使用します。

ExpandedとSizedBoxの違い

ExpandedとSizedBoxは、どちらもウィジェットのサイズを調整するために使用されますが、異なる目的で使用されます。
Expandedは、子ウィジェットのスペースを最大限に広げることを目的としていますが、SizedBoxは、子ウィジェットのサイズを固定することを目的としています。

Expandedの注意点とトラブルシューティング

Expandedが効かない場合の対処法

Expandedが効かない場合、まず親ウィジェットがRowやColumnなどのFlexを継承したウィジェットであるか確認してください。Expandedは、Flexを継承したウィジェットの子要素としてのみ機能します。

Expandedの子ウィジェットがはみ出る場合の対処法

Expandedの子ウィジェットがはみ出る場合は、ウィジェットのサイズを調整するか、Overflowを許容するウィジェット(例えば、SingleChildScrollView)を使用してください。

Q&A

Q1: Expandedウィジェットとは何ですか?

A1: Expandedウィジェットは、Flutterアプリケーションで効果的なレイアウトを実現するために使用されるウィジェットです。親ウィジェットがFlexを継承したウィジェットの子要素として機能し、子ウィジェットのサイズを動的に調整して空きスペースを最大限に利用します。

Q2: ExpandedウィジェットとFlexibleウィジェットの違いは何ですか?

A2: Expandedウィジェットは、Flexibleウィジェットに “flex: 1” がデフォルトで設定されたものです。Expandedは、空きスペースを均等に割り当てるのに対して、Flexibleはflexプロパティを利用して空きスペースの割り当て方を調整できます。適切な使い分けが重要です。

Q3: Expandedウィジェットを使用する際の注意点は何ですか?

A3: Expandedウィジェットを使用する際の注意点として、親ウィジェットがFlexを継承したウィジェットであることが必要です。また、子ウィジェットのサイズや配置を適切に設定することで、レイアウトが崩れないように注意が必要です。トラブルシューティングにも留意し、効率的なレイアウトを実現しましょう。

まとめ

FlutterのExpandedウィジェットは、効果的なレイアウトを実現するために使用されます。親ウィジェットがFlexを継承したウィジェットの子要素として機能し、子ウィジェットのサイズを動的に調整します。ExpandedとFlexibleの違いを理解し、適切に使い分けることが重要です。また、注意点やトラブルシューティングにも留意して、スムーズなレイアウト構築を目指しましょう。

重要なポイント:

  • Expandedは、親ウィジェットがFlexを継承したウィジェットの子要素として機能する。
  • Expandedは、子ウィジェットのサイズを動的に調整して、空きスペースを最大限に利用する。
  • ExpandedとFlexibleの違いを理解し、適切に使い分けることが重要。
  • 注意点やトラブルシューティングに留意して、効率的なレイアウトを実現する。

これらのポイントを押さえて、FlutterのExpandedウィジェットをうまく活用して、効率的で魅力的なアプリケーションの開発を進めましょう。

全ソース

Expanededでflexを変更するパターン

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Expanded with Flex'),
        ),
        body: Column(
          children: [
            Expanded(
              flex: 1,
              child: Container(
                color: Colors.red,
                child: Center(child: Text('Flex 1')),
              ),
            ),
            Expanded(
              flex: 2,
              child: Container(
                color: Colors.green,
                child: Center(child: Text('Flex 2')),
              ),
            ),
            Expanded(
              flex: 3,
              child: Container(
                color: Colors.blue,
                child: Center(child: Text('Flex 3')),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

flexibleを交えたパターン

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Row(
        children: [
          Container(color: Colors.black, width: 100, height: 100),
          Flexible(
            fit: FlexFit.loose,
            child: Container(
              color: Colors.red,
              height: 50,
              width: 50,
              child: Text('Flexible: FlexFit.loose'),
            ),
          ),
          Flexible(
            fit: FlexFit.tight,
            child: Container(
              color: Colors.green,
              height: 50,
              width: 50,
              child: Text('Flexible: FlexFit.tight'),
            ),
          ),
          Expanded(
            child: Container(
              color: Colors.blue,
              height: 50,
              width: 50,
              child: Text('Expanded'),
            ),
          ),
        ],
      ),
    );
  }
}