WWDC22で発表されたSwiftUIのGridとVStack・HStackの違い

WWDC22でSwiftUIにまつわる様々な発表がありました。
NavigationStackやChartsなどが話題ですが、ここではGridについて解説します。
一見、元々あるVStack・HStackとの違いが分かりづらい (Gridを使わなくてもVstack・HStackで完結するように思える) のですが、具体例を交えて紹介していきます。

## 実装するデザイン
今回実装するデザインは以下のようなTextが並んだものです。
<img width="500" alt="17.21.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42150/a881f912-4933-e092-04d0-551380d72df1.png">
`Designed in`と`Assembled in`が右揃えで並んでおり (`California`と`China`も同様)、`Designed in`と`California`が下揃えで並んでいます。
また、`California`と`China`は変数であり、横幅は可変とします。

## VStack・HStackとGridを使った実装例
VStack・HStackを使った実装としては2種類の方法が考えられます。
HStackの中にVStackをレイアウトする方法と、Vstackの中にHStackをレイアウトする方法です。
それぞれの実装したものは次のようになります。
<img width="500" alt="17.43.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42150/a7a9c75e-40bf-f148-9466-bca496caa0ae.png">
`spacing`などを全く設定していないのでVStack・HStackを使った実装はかなりデザインとは異なるものとなってしまっています。

コードは以下のようになります。

① HStackの中にVStackを入れた場合
```swift
HStack(alignment: .bottom) {
    VStack(alignment: .trailing) {
        Text("Designed in")
        Text("Assembled in")
    }
    VStack(alignment: .trailing) {
        Text("California")
            .font(.title)
        Text("China")
            .font(.title)
    }
}
```

② VStackの中にHStackを入れた場合
```swift
VStack(alignment: .trailing) {
    HStack(alignment: .bottom) {
        Text("Designed in")
        Text("California")
            .font(.title)
    }
    HStack(alignment: .bottom) {
        Text("Assembled in")
        Text("China")
            .font(.title)
    }
}
```

③ Gridを使った場合
```swift
Grid(alignment: .trailing) {
    GridRow(alignment: .bottom) {
        Text("Designed in")
        Text("California")
            .font(.title)
    }
    GridRow(alignment: .bottom) {
        Text("Assembled in")
        Text("China")
            .font(.title)
    }
}
```

View Hierarchyを見ると違いが分かりやすいです。
<img width="400" alt="17.44.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42150/9b53aa4f-b7c2-6743-2658-ac73e611aee3.png">
VStack・HStackを使ったものはそれぞれのStack内ではalignmentが効いているのですが、上位のStackとalignmentを効かせることができません。

ただ、VStack・HStackのそれぞれにspacingを入れることで近づけることは可能です。
以下は、①の1つ目のVStackに`spacing: 15`を設定し、②の２つ目のHStackに`spacing: 50`を設定した例です。
<img width="500" alt="17.48.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42150/23d3cf7a-d008-dcc0-ef40-80b2dce8da01.png">
①も②もかなりデザインに沿った実装になりました。
ただ、この場合はspacingの値をハードコードしているため、テキストの内容が変数の場合は、それを計算してspacingを設定する必要が発生します。

## SwiftUIのGridについて
実装例を通してVStack・HStackとGridの違いを見てきました。
Gridは一言で表すとTableのようなもので (WWDC22でTableというレイアウトも発表されましたね)、Tableのように並んだレイアウトをalighmentなど設定するのが得意なものと思います。

逆に以下のようなデザインはGridでは難しく、VStack・HStackを使って実装することになると思います。
<img width="500" alt="18.04.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42150/6f4b5d4f-916c-5f55-98f5-1e61560600c5.png">

今回の実装では使いませんでしたが、Grid内のspacingの設定も可能です。
例えば以下のように設定できます。
```swift
Grid(alignment: .trailing,
     horizontalSpacing: 20,
     verticalSpacing: 10) {
        GridRow(alignment: .bottom) {
        Text("Designed in")
        Text("California")
            .font(.title)
        }
        GridRow(alignment: .bottom) {
        Text("Assembled in")
        Text("China")
            .font(.title)
    }
}
```

また、複数のCellを結合する`.gridCellColumns(_ count:)`などを使えば、より柔軟にレイアウトを構築することができます。
![スクリーンショット 2022-06-18 19.02.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42150/b3d11cf3-73c5-3c9c-7ec7-0b2bd895ff68.png)

より詳しい仕様は[こちら](https://developer.apple.com/documentation/swiftui/grid)にまとまっています。

## まとめ
本記事では、VStack・HStackとGridの違いを紹介しました。
今まで表現しづらかったレイアウトも簡単に表現できるようになったと思います。

本記事では紹介しなかった機能も多くあるため、使えるようになったら積極的に活用していきたいと思います。