【Flutterレイアウト】Expanded、Flexible、Spacer

Flutterレイアウトシリーズのその他の記事
- [Stackの使い方](https://qiita.com/ling350181/items/f5719272a516889bd3bb)
- [FlutterレイアウトのOverlayの使用](https://qiita.com/ling350181/items/cb3623b04a3328f2b125)
- [Flutterのレイアウトを理解する](https://qiita.com/ling350181/items/bfb4b715b56f17f75bb6)
- [FlutterレイアウトのFlex、Row、Column、Wrap、Stackについて](https://qiita.com/ling350181/items/47c8029e53af392f0e5f)
- [FlutterのBoxConstraintsを理解する](https://qiita.com/ling350181/items/9e927826f1164c9205b1)

この記事はFlutterのレイアウトWidgetのExpanded、Flexible、Spacerの使い方を分かりやすく理解するため書いたものです。

※本記事は下記のZenn本にまとめました。

https://zenn.dev/cxj/books/07def04506182d

# Flexibleウィジェット
Flutterのソースコードよると、FlexibleはRow,Column,Flexの子コンポネートとしてしか使えないことは分かります。Flexibleは柔軟に子コンポネートの充填することをコントロールできます。Flexibleの属性は２つのみです。int型のflex、列挙型のFlexFit。
```dart
class Flexible extends ParentDataWidget<FlexParentData> {
  /// Creates a widget that controls how a child of a [Row], [Column], or [Flex]
  /// flexes.
  const Flexible({
    Key? key,
    this.flex = 1,
    this.fit = FlexFit.loose,
    required Widget child,
  }) : super(key: key, child: child);
```

## Flexibleのflex
デフォルトは1,子コンポネート同士はflexの比率より、領域を配り分けます。下記の例を見れば、一目瞭然です。黄色、青色、赤色の比率は1:3:1です。
```dart
return Scaffold(
      body: Center(
        child: Row(
          children: [
            Flexible(
              flex: 1,
              child: Container(
                color: Colors.yellow,
              ),
            ),
            Flexible(
              flex: 3,
              child: Container(
                color: Colors.blue,
              ),
            ),
            Flexible(
              flex: 1,
              child: Container(
                color: Colors.red,
              ),
            )
          ],
        ),
      ),
    );
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2491433/c486aaab-fbd3-0b7b-efbe-9f5164b98e68.png"width="180">
## FlexibleのFlexFit
列挙型のFlexFit,デフォルトはFlexFit.loose
```dart
enum FlexFit {
  tight,
  loose,
}
```
下記の例だと、ColoredBoxの幅の制約はFlexFit.looseになっているため、widthは0になっている。
```dart
Row(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: const [
          SizedBox(
            width: 100,
            child: ColoredBox(
              color: Colors.yellow,
            ),
          ),
          Flexible(
            fit: FlexFit.loose,
            child: ColoredBox(
              color: Colors.blue,
            ),
          ),
          SizedBox(
            width: 100,
            child: ColoredBox(
              color: Colors.red,
            ),
          )
        ],
      ),
```
![スクリーンショット 2022-04-20 16.24.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2491433/b0acc876-d9d5-1613-b3b4-f9d77950d8c7.png)
|FlexFit.loose|FlexFit.tight|
| -- | -- |
|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2491433/fe96126e-c637-7814-403c-9b8256391da0.png"width="180">|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2491433/5b122360-660c-10d4-4f3b-44cdfc033c49.png"width="180">|

使い道としては、Flexibleは子ウィジェットの幅により、柔軟に変化できます。
```dart
return Scaffold(
      body: Row(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: const [
          SizedBox(
            width: 100,
            child: ColoredBox(
              color: Colors.yellow,
            ),
          ),
          Flexible(
            child: ColoredBox(
              color: Colors.blue,
              child: Text("ダミーデータ"),
            ),
          ),
          SizedBox(
            width: 100,
            child: ColoredBox(
              color: Colors.red,
            ),
          )
        ],
      ),
    );
```
|短い文章|長い文章|
| -- | -- |
|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2491433/38ddb6d9-e3ee-20fe-ab54-71982d9e4d07.png"width="180">|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2491433/7b0e8727-f7ed-5d04-0993-3b9bb429c4f1.png"width="180">|

# Expanded
ソースコードによると、ExpandedはFlexibleから継承するウィジェットです。すなわち、ExpandedはFlexFit.tight属性のFlexibleは同じものです。
## コンストラクター
```dart
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({
    Key? key,
    int flex = 1,
    required Widget child,
  }) : super(key: key, flex: flex, fit: FlexFit.tight, child: child);
```

# Spacer
ソースコードによると、SpacerはExpandedを使って、空白の部品を実装したものです。実際に使うと、Spacerは空白を拡大したウィジェットです。
## ソースコード
```dart
 @override
  Widget build(BuildContext context) {
    return Expanded(
      flex: flex,
      child: const SizedBox.shrink(),
    );
  }
```

```dart
return Scaffold(
      body: Row(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: const [
          SizedBox(
            width: 100,
            child: ColoredBox(
              color: Colors.yellow,
            ),
          ),
          Spacer(),
          SizedBox(
            width: 100,
            child: ColoredBox(
              color: Colors.red,
            ),
          )
        ],
      ),
    );
```
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2491433/02dd30f7-db44-7ff9-d33e-c41a2f76bc2e.png"width="180">