Flutter学習メモ: Layouts in Flutter編

# 📖 参考・出典
## 2021年 - これからFlutterを始める人へ学習方法のススメ
- [2021年 - これからFlutterを始める人へ学習方法のススメ](https://zenn.dev/tsuruo/articles/6cc7b5bf24bb65)

↑ 筆者が現時点で一番参考にしている[ツルオカ](https://twitter.com/h_tsuruo)さんの記事です。
本記事の執筆後も、こちらの記事で紹介されている公式ドキュメントを簡単にまとめていこうと思います。

## Layouts in Flutter
- [Layouts in Flutter]
(https://flutter.dev/docs/development/ui/layout)
- [［Flutter］ MainAxisAlignment と CrossAxisAlignment の利用方法](https://qiita.com/kaleidot725/items/35f6940e594bdf073eb8)

***

# Layouts in Flutter

Flutterにおける**Widget**は、**可視オブジェクト**(=**Visible Widget**, View)である画像・アイコン・テキストだけでなく、可視オブジェクトを横・縦・グリッド状に整列(+グループ化)させる**不可視オブジェクト**(=**Layout Widget**, ViewGroup)も含み、「ほぼ全てのもの」が"Widget"として扱われる。

なお、FlutterのWidgetをテキストで確認したい場合は[Widget Catalog](https://flutter.dev/docs/development/ui/widgets)、動画で確認したい場合は[Flutter Widget of the Week](https://www.youtube.com/playlist?list=PLjxrf2q8roU23XGwz3Km7sQZFTdB996iG)を参照する。

以下に、ウィジェットを組み合わせて作成したレイアウト例を示す。
![lakes-icons.png](https://flutter.dev/assets/images/docs/ui/layout/lakes-icons.png)

上記レイアウトに境界線を表示させると以下のようになる。
![lakes-icons-visual.png]
(https://flutter.dev/assets/images/docs/ui/layout/lakes-icons-visual.png)

また、上記レイアウトのウィジェットツリーは以下のようになる。
![sample-flutter-layout.png]
(https://flutter.dev/assets/images/docs/ui/layout/sample-flutter-layout.png)

**Container**は子Widgetにパディングやマージン、枠線、背景色を追加する場合に利用する。
上記の例では、Tab Barの*'CALL,' 'ROUTE,' 'SHARE'*間に**パディング**が設定され、各Tabのテキストに**マージン**が設定されていることがわかる。

## ウィジェットの配置方法

大まかな流れは以下の通り。

1. [Layout Widget](https://flutter.dev/docs/development/ui/widgets/layout)を選択する
2. 選択した[Layout Widget](https://flutter.dev/docs/development/ui/widgets/layout)にVisible Widgetを追加する
3. [build()](https://api.flutter.dev/flutter/widgets/StatelessWidget/build.html)メソッドでインスタンス化(※)する

※ Materialライブラリを利用する場合は、MaterialApp内のScaffoldのbodyプロパティに記述する

### ウィジェットの整列

ウィジェットを縦または横の一列に配置する場合は、それぞれ**[Column](https://api.flutter.dev/flutter/widgets/Column-class.html)**・**[Row](https://api.flutter.dev/flutter/widgets/Row-class.html)**を利用する。
これらのLayout Widgetには、以下のように**Main Axis**と**Cross Axis**という概念が存在し、x/y方向の配置を[mainAxisAlignment](https://api.flutter.dev/flutter/rendering/MainAxisAlignment-class.html)と[crossAxisAlignment](https://api.flutter.dev/flutter/rendering/CrossAxisAlignment-class.html)プロパティで定義することができる。

| ![column-diagram.png](https://flutter.dev/assets/images/docs/ui/layout/column-diagram.png) | ![row-diagram.png](https://flutter.dev/assets/images/docs/ui/layout/row-diagram.png) |
|:--:|:--:|

| 分類 | 列挙型プロパティ | 内容 |
|:-:|:-:|:-:|
| Main/Cross | start | 開始位置寄り |
| ^ | center | 中央寄り |
| ^ | end | 終了位置寄り |
| Main | spaceBetween | 均等配置<br>(開始・終了の前後にスペースなし) |
| ^ | spaceAround | 均等配置<br>(開始・終了の前後にスペース[^1]あり) |
| ^ | spaceEvenly | 均等配置<br>(開始・終了の前後にスペース[^2]あり) |
| Cross | baseline | ベースライン揃え |
| ^ | stretch | Cross方向のサイズ揃え |

[^1]: Main Axis方向に子Widget **半個分**のスペースが挿入
[^2]: Main Axis方向に子Widget **1個分**のスペースが挿入

### ウィジェットのサイズ調整

スクリーンに対してコンテンツがオーバーフローする場合は、以下のように警告が表示される。
![layout-too-large.png]
(https://flutter.dev/assets/images/docs/ui/layout/layout-too-large.png)

オーバーフローを防ぐためには、**スクリーンの範囲内でVisible Widgetを伸縮させる**[Expanded](https://api.flutter.dev/flutter/widgets/Expanded-class.html)ウィジェットを活用する。

また、以下のようにウィジェット間でサイズ比率を固定したい場合は[Expanded](https://api.flutter.dev/flutter/widgets/Expanded-class.html)クラスの[flex](https://api.flutter.dev/flutter/widgets/Flexible/flex.html)プロパティ(既定値:1)で比率を定義する。
![row-expanded-visual.png]
(https://flutter.dev/assets/images/docs/ui/layout/row-expanded-visual.png)

### ウィジェットのパッキング(詰めて配置)

以下のようにウィジェットを詰めて配置する場合、[Column](https://api.flutter.dev/flutter/widgets/Column-class.html)・[Row](https://api.flutter.dev/flutter/widgets/Row-class.html)の[mainAxisSize](https://api.flutter.dev/flutter/widgets/Flex/mainAxisSize.html)プロパティに[MainAxisSize](https://api.flutter.dev/flutter/rendering/MainAxisSize-class.html)の列挙型プロパティminを設定する。
![packed.png]
(https://flutter.dev/assets/images/docs/ui/layout/packed.png)

また、画像をWidgetとして表示する場合、[Image.network()](https://api.flutter.dev/flutter/widgets/Image/Image.network.html)を用いてネットワーク経由で画像を取得するか、プロジェクトフォルダに保存して格納先パスを**pubspec.yaml**ファイルに記述した上で[Image.asset()](https://api.flutter.dev/flutter/widgets/Image/Image.asset.html)を用いてローカル経由で画像を取得する方法がある。

### 一般的なLayout Widget

一般的な[Layout Widget](https://flutter.dev/docs/development/ui/widgets/layout)を以下に示す。

| ライブラリ | Widget | 内容 | 例 |
|:-:|:-:|:-:|:-:|
| Standard<br>(標準) | [Container](https://api.flutter.dev/flutter/widgets/Container-class.html) | Visible Widgetに対する<br>余白・枠線・背景色など<br>各種装飾の付加 | ![margin-padding-border.png](https://flutter.dev/assets/images/docs/ui/layout/margin-padding-border.png) |
| ^ | [GridView](https://api.flutter.dev/flutter/widgets/GridView-class.html) | スクロール可能な<br>グリッドレイアウト | ![gridview-count-flutter-gallery.png](https://flutter.dev/assets/images/docs/ui/layout/gridview-count-flutter-gallery.png) |
| ^ | [ListView](https://api.flutter.dev/flutter/widgets/ListView-class.html) | スクロール可能な<br>リストレイアウト | ![listview.png](https://flutter.dev/assets/images/docs/ui/layout/listview.png) |
| ^ | [Stack](https://api.flutter.dev/flutter/vm_service/Stack-class.html) | Widgetのz方向への<br>重ね合わせ | ![stack.png](https://flutter.dev/assets/images/docs/ui/layout/stack.png) |
| Material | [Card](https://api.flutter.dev/flutter/material/Card-class.html) | カード状にWidgetを配置 | ![card-flutter-gallery.png](https://flutter.dev/assets/images/docs/ui/layout/card-flutter-gallery.png) |
| ^ | [ListTile](https://api.flutter.dev/flutter/material/ListTile-class.html) | マテリアルデザイン仕様の<br>ListView | ![listtile-flutter-gallery.png](https://flutter.dev/assets/images/docs/ui/layout/listtile-flutter-gallery.png) |