Flutterの公式ドキュメントを読んで理解する 〜Building layouts/Understanding constraints〜

# 今回読んだページ
https://flutter.dev/docs/development/ui/layout/constraints

# 個人的なまとめ
* Widgetは、自身の**制約**を、その**親**から取得する。
* 制約は、最小・最大の幅と、最小・最大の高さの、4つのdoubleのセットである。
* `ConstrainedBox`は親から受けとった制約に**追加の**制約を課すだけである。

# Understanding constraints
<img src="https://flutter.dev/assets/ui/layout/article-hero-image-6e652a29e00456a5fc7b1acc340673115904c87e6003bbeed3523bfef794e540.png" />

>制約は下がる。（階層的な意味か？？）
サイズは上がる。
親が位置をセットする。

Flutterを学習している人から「`width:100`をセットしたWidgetが100pxの幅でないことがあるのは何故か」と尋ねられたとき、デフォルトの答えは、そのWidgetを`Center`に配置するように指示することである。

**そんなことしないで！！**

もしそうした場合、彼らは何度も戻ってきて、何故`FittedBox`が動かないのか、何故`Column`がはみ出るのか、あるいは、`IntrinsicWidth`が行うことになっていることを尋ねてくる。

代わりに、まずFlutterのレイアウトはHTMLのレイアウトとは大きく違うことを教えて、次に以下のようなルールを覚えさせる。

## Constraints go down. Sizes go up. Parent sets position.
このルールを知らないと、Flutterのレイアウトを本当に理解することはできないので、
Flutterの開発者たちは早い段階でこれを学ぶべきである。

##### 詳細：
* Widgetは、自身の**制約**を、その**親**から取得する。制約は、最小・最大の幅と、最小・最大の高さの、4つのdoubleのセットである。
* それから、そのWidgetは自身の子リストを通過する。そのWidgetは1つずつ子の制約が何かを教え（子によって異なる可能性がある）、各子にどのくらいのサイズが欲しいか尋ねる。
* そして、そのWidgetは子たちを1つずつ配置する。
* 最後に、そのWidgetは、その親に自身のサイズを伝える(もちろん、元の制約の範囲内で)。

例えば、構成されたWidgetがいくらかのpaddingを持ったColumnを含み、2つの子たちを以下のように配置したい場合：

<img src="https://flutter.dev/assets/ui/layout/children-b0b5973c79a94409aa1ac91f8395cc8d67a8d134259e6d0f0c5202ce573e532b.png" />

交渉は次のようになる。
**Widget:** 「親よ、私の制約はなんですか？」
**Parent:** 「幅は90~300pxで、高さは30~85だよ。」 
**Widget:** 「うーん、5pxのpaddingが欲しいから、私の子供達は最大で290pxの幅と75pxの高さを持てますね。」
**Widget:** 「1番目の子よ、君は0~290pxの幅、0~75pxの高さである必要があるよ。」
**First child:** 「OKです。でしたら290pxの幅と、20pxの高さが欲しいです。」
**Widget:** 「うーん、2番目の子は1番目の子の下におきたいので、2番目の子の高さは55pxしか残っていません。」
**Widget:** 「2番目の子よ、君は0~290の幅、0~55pxの高さである必要があるよ。」
**Second child:** 「OKです、140pxの幅と、30pxの高さが欲しいです。」
**Widget:** 「結構。 1番目の子の位置は`x:5, y:5`で、2番目の子の位置は`x:80,y:25`です。」
**Widget:** 「親よ、私のサイズは300pxの幅と、60pxの高さに決めました。」

## Limitations
上述したレイアウトのルールの結果、Flutterのレイアウトエンジンには、いくつかの重要な制限がある。

* Widgetは、その親から得た制約内でのみ自身の大きさを決定できる。これは、Widgetはたいてい**必要なサイズにすることはできない**ことを意味する。
* Widgetの位置を決定するのはその親なので、Widgetは**スクリーン内の自身の位置を知らないし、決定することもできない。**
* 同様に、親の大きさと位置はそのさらに親（親の親）に依存するので、ツリー全体を考慮せずにWidgetのサイズと位置を正確に定義することは不可能である。

## Examples
インタラクティブな体験をするには、以下のDartPaｄを使用する。(ここで使っているのはCodePen)
番号つきの水平スクロールバーを使用して、29個の様々な例を切り替える。

<p class="codepen" data-height="780" data-theme-id="dark" data-default-tab="js,result" data-user="popy1017" data-slug-hash="pojYNZx" data-preview="true" style="height: 780px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="flutter-constraints-example29">
  <span>See the Pen <a href="https://codepen.io/popy1017/pen/pojYNZx">
  flutter-constraints-example29</a> by popy1017 (<a href="https://codepen.io/popy1017">@popy1017</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

各例については、以下で説明する。

### Example 1
<img src="https://flutter.dev/assets/ui/layout/layout-1-825be104de7d817a387201bc562d98618eb59c53e9c606552b39a4dceb51332d.png" />

```dart
Container(color: Colors.red)
```
スクリーンは`Container`の親で、`Container`にスクリーンと正確に同じサイズであることを強制している。
したがって、`Container`はスクリーンを赤く塗りつぶしている。

### Example 2
<img src="https://flutter.dev/assets/ui/layout/layout-2-825be104de7d817a387201bc562d98618eb59c53e9c606552b39a4dceb51332d.png" />

```dart
Container(width: 100, height: 100, color: Colors.red)
```
赤い`Container`は100x100を希望したが、スクリーンがスクリーンと同じサイズになるように強制しているためそれはできない。
そのため、`Container`はスクリーンを塗りつぶしている。

#### 補足
コードを読むと、(100行目あたりから)

```dart
  child: Container(
    width: 400,
    height: 670,
    color: Color(0xFFCCCCCC),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Expanded(
          child: ConstrainedBox(
            constraints: BoxConstraints.tightFor(
              width: double.infinity, height: double.infinity),
            child: widget.examples[count - 1] // <- これが赤い部分
          )
        ),
```
となっているので、この`Container`の親は`ConstrainedBox`である。（Deeply nested...）

```
1. Container： 制約(width: 400, height: 670)
↓
2. Column: 制約（指定なし）
↓
3. Expanded： 制約（指定なし）
↓
4. ConstrainedBox: 
  制約（BoxConstraints.tightFor(
        width: double.infinity,
        height: double.infinity
      )
  ）
↓
5. Container(赤い部分): 制約（width:100, height:100）
```
「スクリーンと正確に同じサイズであることを強制している」と言っているのが4番目の`ConstrainedBox`である。
このWidgetでは、`ConstrainedBox.constraints`に`BoxConstraints.tightFor`が指定されており、こいつの役割は、「子のサイズを、指定した幅と高さに固定する」というもの。
ここで指定されている幅と高さは両方とも`double.infinity`であり、子を可能な限り大きくするという意味になる。
この例では、親である`ConstrainedBox`の「可能な限り大きくなれよ」という命令に対し、子は「100x100がいいです」と言っているため、それは聞き入れてもらえず、結果的に可能な限り大きくなった。（のだと思われる。）

### Example 3
<img src="https://flutter.dev/assets/ui/layout/layout-3-f5a51de376d567e306fc8c343027af49ebccb8e568889a3f739623e1de282361.png" />

```dart
Center(
   child: Container(width: 100, height: 100, color: Colors.red)
)
```
スクリーンは、`Center`に対して正確にスクリーンと同じサイズであることを強制しているので、`Center`はスクリーン全体に表示されている。

`Center`は`Container`に、スクリーン（400x670）より大きくはできないけど、どんなサイズでも良いよと言っている。
そのため、`Container`は100x100となっている。

### Example 4
<img src="https://flutter.dev/assets/ui/layout/layout-4-daf26336d8ae858d355cfb480a7491757a945575498146bfcfdedef633597f50.png" />

```dart
Align(
   alignment: Alignment.bottomRight,
   child: Container(width: 100, height: 100, color: Colors.red),
)
```
これは、`Center`の代わりに`Align`を使っている点で、前の例とは異なっている。

`Align`も`Container`に、サイズは何でも良いと言っているが、空のスペースがある場合は、コンテナを中央に配置しない。（`Alignment.bottomRight`が指定されているので）
代わりに、`Container`を利用可能スペースのな右下に揃えている。

### Example 5
<img src="https://flutter.dev/assets/ui/layout/layout-5-688839ab6c793c65bf77a0eca8c3a6233a5869eb6b498a4af7bfe500a47be698.png" />

```dart
Center(
   child: Container(
      color: Colors.red,
      width: double.infinity,
      height: double.infinity,
   )
)
```
スクリーンは、`Center`に対して正確にスクリーンと同じサイズであることを強制しているので、`Center`はスクリーン全体に表示されている。

`Center`は`Container`に、スクリーンより大きくなければ、どんなサイズでも良いとしている。
`Container`は無限のサイズを御所望だが、スクリーンよりは大きくなれないので、結果的にスクリーン全体を赤く色付けている。

### Example 6
<img src="https://flutter.dev/assets/ui/layout/layout-6-6327730032a201dd51d4fcc71976fefb40cc10e782ca9e743237331a5d9193e4.png" />

```dart
Center(child: Container(color: Colors.red))
```
スクリーンは、`Center`に対して正確にスクリーンと同じサイズであることを強制しているので、`Center`はスクリーン全体に表示されている。

`Center`は`Container`にスクリーンより大きくはできないけど、好きなサイズで良いと言っている。
`Container`は子を持たず、固定されたサイズもないので、可能な限り大きくすると決めた結果、スクリーン全体を満たしている。

しかし、何故`Container`がそれを決めるのだろう？
単純に`Container`widgetを作った人による設計上の決定だからである。
これは異なる方法で作成された可能性があり、[コンテナのドキュメント](https://api.flutter.dev/flutter/widgets/Container-class.html)を読んで動作を理解する必要がある。

### Example 7
<img src="https://flutter.dev/assets/ui/layout/layout-7-036b51e02f921a870261a641b5913036b3d6957352756d03eb6e31ebbfe07997.png" />

```dart
Center(
   child: Container(
      color: Colors.red,
      child: Container(color: Colors.green, width: 30, height: 30),
   )
)
```
スクリーンは、`Center`に対して正確にスクリーンと同じサイズであることを強制しているので、`Center`はスクリーン全体に表示されている。

`Center`は赤い`Container`にスクリーンより大きくはできないけど、好きなサイズで良いと言っている。
赤い`Container`はサイズは持たないが、子を持っていて、子と同じサイズであることを決めている。

赤い`Container`はその子に、スクリーンよりは大きくできないけど、希望するサイズで良いと言っている。
その子は、30x30を希望する緑の`Container`である。
赤い`Container`は、自身のサイズを子のサイズに合わせてサイズ調整するため、30x30になる。
緑の`Container`は赤い`Container`を覆ってしまうので、赤色は見えない。

>"Sizes go up"とはこういうことなのか。

### Example 8
<img src="https://flutter.dev/assets/ui/layout/layout-8-07a271faf7e3042fd77609563f794743c1d196555ea1eb4dfa4c6d589440e9bf.png" />

```dart
Center(
   child: Container(
     color: Colors.red,
     padding: const EdgeInsets.all(20.0),
     child: Container(color: Colors.green, width: 30, height: 30),
   )
)
```
赤い`Container`は、自身の大きさをその子の大きさに合わせるが、自身のpaddingが考慮される。
そのため、30x30 + paddingとなる。
paddingのおかげで赤色は見えていて、緑の`Container`は前のサンプルと同じ大きさである。

### Example 9
<img src="https://flutter.dev/assets/ui/layout/layout-9-12c5e7ff078748e83f7c042b2c186554848696981640e595b59a2c76d50cd7fb.png" />

```dart
ConstrainedBox(
   constraints: BoxConstraints(
      minWidth: 70, 
      minHeight: 70,
      maxWidth: 150, 
      maxHeight: 150,
   ),
   child: Container(color: Colors.red, width: 10, height: 10),
)
```
`Container`は70〜150pxでなければならない、と推測するかもしれないが、それは間違いである。
`ConstrainedBox`は親から受けとった制約に**追加の**制約を課すだけである。
ここでは、スクリーンは`ConstrainedBox`にスクリーンと正確に同じ大きさであることを強制しているため、それは子である`Container`にもスクリーンのサイズであるべきであると伝える。
したがって、`constraints`パラメータは無視される。

### Example 10
<img src="https://flutter.dev/assets/ui/layout/layout-10-9eda3f2fee73514954cfeb7e6114607c5deb34ce9060f2e6bbd96c5018aa1281.png" />

```dart
Center(
   child: ConstrainedBox(
      constraints: BoxConstraints(
         minWidth: 70, 
         minHeight: 70,
         maxWidth: 150, 
         maxHeight: 150,
      ),
      child: Container(color: Colors.red, width: 10, height: 10),
   )    
)
```
ここでは、`Center`により`ConstrainedBox`を画面サイズまでの任意のサイズにすることができる。
`ConstrainedBox`は子に対して、`constraints`パラメータから**追加の**制約を課している。

`Container`は70~150pxでなければならない。
それは、10x10を希望しているので、最終的には最小値である70pxになる。

### Example 11
<img src="https://flutter.dev/assets/ui/layout/layout-11-f4ff5df4b9fc91cb0377847beb4792d3caef5da34e038bd8ccab51c7806c8568.png" />

```dart
Center(
  child: ConstrainedBox(
     constraints: BoxConstraints(
        minWidth: 70, 
        minHeight: 70,
        maxWidth: 150, 
        maxHeight: 150,
        ),
     child: Container(color: Colors.red, width: 1000, height: 1000),
  )  
)
```
> Example 10の逆パターンで、制約である大きさを超えて指定された場合の挙動。
この場合は、maxWidthやmaxHeightで指定した大きさになる。

`Center`により`ConstrainedBox`を画面サイズまでの任意のサイズにすることができる。
`ConstrainedBox`は子に対して、`constraints`パラメータから**追加の**制約を課している。

`Container`は70~150pxである必要があるが、1000pxを希望しているため、最終的には(制約の)最大値である150になる。

### Example 12
<img src="https://flutter.dev/assets/ui/layout/layout-12-462e922c3aa05323b09f21bdbbd470d430e5a73e39c171c9e9b641a9eb0fe59a.png" />

```dart
Center(
   child: ConstrainedBox(
      constraints: BoxConstraints(
         minWidth: 70, 
         minHeight: 70,
         maxWidth: 150, 
         maxHeight: 150,
      ),
      child: Container(color: Colors.red, width: 100, height: 100),
   ) 
)
```
> Example10とExample11は制約の範囲(min~max)を満たさない場合の挙動だったが、
Example12は制約の範囲を満たす場合の挙動

`Center`により`ConstrainedBox`を画面サイズまでの任意のサイズにすることができる。
`ConstrainedBox`は子に対して、`constraints`パラメータから**追加の**制約を課している。

`Container`は70~150pxである必要があるが、100pxを希望していて、それは70~150pxの間であるので、100pxとなっている。

### Example 13
<img src="https://flutter.dev/assets/ui/layout/layout-13-4c362ad0c0eb21c9f1e6c3d408bf388ef11c74c0b4290d390641f082a5f8d39a.png" />

```dart
UnconstrainedBox(
   child: Container(color: Colors.red, width: 20, height: 50),
)
```
スクリーンは`UnconstrainedBox`に正確にスクリーンと同じサイズであることを強制している。
しかし、`UnconstrainedBox`を使うと、子である`Container`を任意のサイズにすることができる。

### Example 14
<img src="https://flutter.dev/assets/ui/layout/layout-14-db623a0d2fdcb54b91458487e16835bd5d465cb31d5e9cdcffb1975ae260ef8a.png" />

```dart
UnconstrainedBox(
   child: Container(color: Colors.red, width: 4000, height: 50),
)
```
スクリーンは`UnconstrainedBox`に正確にスクリーンと同じサイズであることを強制し、`UnconstrainedBox`を使うと、子である`Container`を任意のサイズにすることができる。

残念ながら、この場合、`Container`は4000pxの幅で`UnconstrainedBox`に収まりきらないので、警告が出ている。

### Example 15
<img src="https://flutter.dev/assets/ui/layout/layout-15-69a65a0e8f124a5b8f1558a670cc1d682e4e1de9966472fd4fc09566a8670273.png" />

```dart
OverflowBox(
   minWidth: 0.0,
   minHeight: 0.0,
   maxWidth: double.infinity,
   maxHeight: double.infinity,
   child: Container(color: Colors.red, width: 4000, height: 50),
);
```
スクリーンは、`OverflowBox`に同じサイズであることを強制し、`OverflowBox`はその子である`Container`に任意のサイズを許容している。

`OverflowBox`は`UnconstrainedBox`と似ており、違いは、子がスペースに合わなくても決して警告を出さないことである。

この場合、`Container`は4000pxの幅を持ち、`OverflowBox`のサイズを超えているが、`OverflowBox`は警告を出さずに、可能な限り表示している。

>（やっと半分か。。。）

### Example 16
<img src="https://flutter.dev/assets/ui/layout/layout-16-d283890cf994b0ba0a2fb1447d69fac49c9a5e3dbc0d186759840af18538b957.png" />

```dart
UnconstrainedBox(
   child: Container(
      color: Colors.red, 
      width: double.infinity, 
      height: 100,
   )
)
```
何も表示されず、コンソールにエラーが表示されるだろう。

`UnconstrainedBox`を使うと、その子が任意のサイズになるようにできるが、子である`Container`が無限のサイズを指定している。

Flutterは無限のサイズは描画できないため、以下のようなメッセージでエラーを投げる:
`BoxConstraints forces an infinite width.`

### Example 17
<img src="https://flutter.dev/assets/ui/layout/layout-17-f5a51de376d567e306fc8c343027af49ebccb8e568889a3f739623e1de282361.png" />

```dart
UnconstrainedBox(
   child: LimitedBox(
      maxWidth: 100,
      child: Container( 
         color: Colors.red,
         width: double.infinity, 
         height: 100,
      )
   )
)
```
ここではもうエラーは発生しない。
`LimitedBox`が`UnconstrainedBox`によって無限のサイズを与えられると、`LimitedBox`はその子に対して100pxの最大幅を渡しているからである。

`UnconstrainedBox`を`Center`widgetに変えると、`LimitedBox`はその制限を適用しなくなり(その制約は`LimitedBox`が無限の制約を受け取ったときのみ適用されるため)、`Container`の幅は、100を超えて拡大できる。

これは、`LimitedBox`と`ConstrainedBox`の違いを説明している。

### Example 18
<img src="https://flutter.dev/assets/ui/layout/layout-18-b51ef01de37fd2f12335919c5500258b5ed967a2d9d7de1747bedc48b4580049.png" />

```dart
FittedBox(
   child: Text('Some Example Text.'),
)
```
スクリーンは、`FittedBox`にスクリーンと正確に同じサイズであることを強制する。
テキストには、テキストの量やフォントサイズなどに応じた自然な幅がある。

`FittedBox`を使うと、`Text`が任意のサイズとなるようにできるが、
`Text`がそのサイズを`FittedBox`に伝えた後で、`FittedBox`はすべての利用可能な幅を満たすまで`Text`を拡大する。


### Example 19
<img src="https://flutter.dev/assets/ui/layout/layout-19-05bfac93ef75f570c3aab05f5ce96dff55784f413b0a842aeca3764c6ec095e8.png" />

```dart
Center(
   child: FittedBox(
      child: Text('Some Example Text.'),
   )
)
```
しかし、`FittedBox`を`Center`widgetの中に入れると何が起こるだろう？
`Center`を使うと、`FittedBox`はスクリーンのサイズまでの任意のサイズになることができるようになる。

`FittedBox`は自身を`Text`と大きさを合わせ、`Text`が任意のサイズとなれるようにしている。
`FittedBox`と`Text`が両方とも同じ大きさであるため、拡大は起こらない。

### Example 20
<img src="https://flutter.dev/assets/ui/layout/layout-20-4e6bf6e9bfd1136a132ba3c0dc31848d8b954085835d026afbdce73c2c75922e.png" />

```dart
Center(
   child: FittedBox(
      child: Text('This is some very very very large text that is too big to fit a regular screen in a single line.'),
   )
)
```
しかし、`FittedBox`は`Center`widgetの中にあるが、`Text`がスクリーンに収まりきらない場合はどうなるだろう？

`FittedBox`は自身のサイズを`Text`に合わせようとするが、スクリーンより大きくなることはできない。
そのため、スクリーンのサイズとなり、`Text`もスクリーンに合わせてサイズ変更される。

### Example 21
<img src="https://flutter.dev/assets/ui/layout/layout-21-6fea0a82ddd89f85dc29799961b0fe489ee1650f15df320154969e1fb5c89f9b.png" />

```dart
Center(
   child: Text('This is some very very very large text that is too big to fit a regular screen in a single line.'),
)
```
しかし、`FittedBox`を削除した場合、`Text`はスクリーンから最大幅を取得し、画面に合わせて改行する。

### Example 22
<img src="https://flutter.dev/assets/ui/layout/layout-22-d26f52ccbf538a3ccc2396825b4288b4c22ec18c134462990165ddc972761de9.png" />

```dart
FittedBox(
   child: Container(
      height: 20.0, 
      width: double.infinity,
   )
)
```
`FittedBox`は(無限でないwidthとheightを持つ)境界付きのWidgetのみをスケールする。
それ以外は何も描画せず、コンソールにエラーが表示される。


### Example 23
<img src="https://flutter.dev/assets/ui/layout/layout-23-e87bffdd10eaf8efa4e3e8ee1d4b706ec57421fb5d61181856af558ea40fabce.png" />

```dart
Row(
   children:[
      Container(color: Colors.red, child: Text('Hello!')),
      Container(color: Colors.green, child: Text('Goodbye!')),
   ]
)
```
スクリーンは、`Row`にスクリーンと同じサイズになるように強制する。

`UnconstrainedBox`のように、`Row`はその子たちに対してなんの制約も課さない代わりに、任意のサイズになれるようにする。
`Row`はそれらを横に並べるので、余りのスペースは空のままとなる。

### Example 24
<img src="https://flutter.dev/assets/ui/layout/layout-24-ac141e591bcb83a056edd49cc8b33ac90937b40e2d112338cfca67c11cff8ed3.png" />

```dart
Row(
   children:[
      Container(color: Colors.red, child: Text('This is a very long text that won’t fit the line.')),
      Container(color: Colors.green, child: Text('Goodbye!')),
   ]
)
```
`Row`はchildrenに何の制約も課さないので、子が大きすぎて`Row`の使用可能な幅に収まらない可能性がある。
この場合、`UnconstrainedBox`のように、`Row`は"overflow warning"を表示する。

### Example 25
<img src="https://flutter.dev/assets/ui/layout/layout-25-c5e2476cf27ce8247a44f393080ca2827ebfc4e99b77ad119ba7cc28e5e8fc09.png" />

```dart
Row(
   children:[
      Expanded(
         child: Container(color: Colors.red, child: Text('This is a very long text that won’t fit the line.'))
      ),
      Container(color: Colors.green, child: Text('Goodbye!')),
   ]
)
```
`Row`の子が`Expanded`widgetにラップされているとき、`Row`はこの子に自身の幅を定義させない。

代わりに、他の子に応じて`Expanded`の幅を定義し、`Expanded`widgetは子に`Expanded`の幅を持つよう強制する。

言い換えれば、`Expanded`を使うと、元の子の幅は無関係となり無視される。

### Example 26
<img src="https://flutter.dev/assets/ui/layout/layout-26-51aa83223076538af35894fd5703c79e73eb25c26ce597c916a898b39f018ee2.png" />

```dart
Row(
   children:[
      Expanded(
         child: Container(color: Colors.red, child: Text(‘This is a very long text that won’t fit the line.’)),
      ),
      Expanded(
         child: Container(color: Colors.green, child: Text(‘Goodbye!’),
      ),
   ]
)
```
`Row`のすべてのchildrenが`Expanded`widgetにラップされている場合、各`Expanded`はそのflexパラメータに比例するサイズを持ち、各`Expanded`はchildに対して`Expanded`と同じ幅を持つことを強制する。

言い換えれば、`Expanded`はchildrenの適切な幅を無視する。

### Example 27
<img src="https://flutter.dev/assets/ui/layout/layout-27-5e53973bea23aeb72fe4cee4f726aec0c8c1ac50915fdd31834b44ef9834d769.png" />

```dart
Row(children:[
  Flexible(
    child: Container(color: Colors.red, child: Text('This is a very long text that won’t fit the line.'))),
  Flexible(
    child: Container(color: Colors.green, child: Text(‘Goodbye!’))),
  ]
)
```
`Expanded`の代わりに`Flexible`を使った場合の唯一の違いは、
`Flexible`を使うと、childが`Flexible`と同じか小さい幅を持つようになることである。(`Expanded`はchildに、同じ幅を持つよう強制する)
しかし、`Expanded`と`Flexible`は両方とも、自身のサイズ変更時にchildrenの幅を無視する。

>Note: つまり、`Row`の子をサイズに比例して拡張することはできない。
`Row`は、正確なchildの幅を使うか、`Expanded`やFlexible`を使う時は完全に無視するかである。

### Example 28
<img src="https://flutter.dev/assets/ui/layout/layout-28-ff269c46d854e5777421c6522d90599d4d76d27c0cd302bdce95f2348b9d99b3.png" />

```dart
Scaffold(
   body: Container(
      color: blue,
      child: Column(
         children: [
            Text('Hello!'),
            Text('Goodbye!'),
         ]
      )))
```
スクリーンは`Scaffold`にスクリーンと全く同じサイズであることを強制しているので、`Scaffold`はスクリーンを満たしている。
`Scaffold`は`Container`に、スクリーンよりは大きくなれないけど、任意のサイズで良いとと伝えている。

>Note: あるWidgetがそのchildに対してある大きさよりも小さくなれるよと伝えるとき、我々はWidgetがその子に**緩やかな**制約を提供する、と言う。詳しくはあとで。


### Example 29
<img src="https://flutter.dev/assets/ui/layout/layout-29-d1857867feb3a9d8ba2a5f90d186441866046037eec682be6bab1d90acb9d1f6.png" />

```dart
Scaffold(
body: SizedBox.expand(
   child: Container(
      color: blue,
      child: Column(
         children: [
            Text('Hello!'),
            Text('Goodbye!'),
         ],
      ))))
```
`Scaffold`のchildに`Scaffold`のサイズと全く同じになって欲しいとするなら、
`SizedBox.expand`で子をラップすることで実現できる。

>Note: あるWidgetがそのchildにあるサイズである必要があると伝えるとき、我々はwidgetがその子に対して**厳しい**制約を与える、と言う。

## Tight vs loose constraints
制約が「厳しい」または「緩い」と聞くのはあまりに一般的なので、その意味を知っておく価値がある。

「厳しい」制約は、単一の可能性、正確なサイズを提供する。
つまり、厳しい制約は、その最大幅と最小幅が同じであり、最大の高さと最小の高さも同じであるということである。

Flutterの`box.dart`ファイルを見て、`BoxConstraints`コンストラクタを検索すると、以下のようなものが見つかる：

```dart
BoxConstraints.tight(Size size)
   : minWidth = size.width,
     maxWidth = size.width,
     minHeight = size.height,
     maxHeight = size.height;

```
もう1度、上記のExample 2を見ると、スクリーンは赤い`Contaner`に、スクリーンと全く同じサイズであることを強制していることがわかる。
もちろん、スクリーンは`Container`に対して厳しい制約を渡すことによってそれを行う。

一方で、「緩い」制約は、**最大の**幅と高さは指定するが、widgetが望む限り小さくなることを許す。
言い換えれば、緩い制約は**最小の**幅と高さが両方とも**0**であるということである。

```dart
BoxConstraints.loose(Size size)
   : minWidth = 0.0,
     maxWidth = size.width,
     minHeight = 0.0,
     maxHeight = size.height;
```
もう1度Example 3を見ると、`Center`が赤い`Container`を画面より小さくすることを許していることがわかる。
もちろん、`Center`は`Container`に緩い制約を渡すことでそれを行っている。
結局のところ、`Center`の目的は、親(スクリーン)から受け取った厳しい制約を、その子(`Container`)に対して緩い制約に変換することである。

## Learning the layout rules for specific widgets
一般的なレイアウトルールを知ることは必要だが、それだけでは不十分である。

一般的なルールを適用するとき、各Widgetには多くの自由があるので、Widgetの名前を読むだけで何ができるのかを知る方法はない。

推測しようとしても、きっと間違えてしまうだろう。
ドキュメントを読んだり、ソースコードを勉強しない限りは、あるwidgetがどう動くかを正確に知ることはできない。

レイアウトのソースコードはたいてい複雑であるため、おそらくドキュメントを読んだほうが良いだろう。
しかし、レイアウトのソースコードを勉強すると決めたのであれば、IDEのナビゲーション機能を使って簡単に探すことができる。

ここに例を示す：

* コードから`Column`を見つけ、ソースコードに移動する。これを行うには、Android StudioかIntelliJで`command+B`(macOS)あるいは`control+B`(Windows/Linux)を使う。`basic.dart`に移動するだろう。`Column`は`Flex`の拡張なので、`Flex`のソースコードに移動する(`basic.dart`の中)。
* `createRenderObject()`と呼ばれる関数を見つけるまでスクロールする。見るとわかるように、この関数は`RenderFlex`を返す。これは`Column`のレンダーオブジェクトである。ここで、`RenderFlex`のソースコードに移動する。`flex.dart`ファイルに移動するだろう。
* `performLayout()`関数を見つけるまでスクロールする。これは、`Column`のレイアウトを行う関数である。

<img src="https://flutter.dev/assets/ui/layout/layout-final-c658630c2a873c21e14ca57134e0f7a0283fc921e778b542cd2c353946171721.png" />