【SwiftUI】NavigationViewからNavigationStackへの移行

# はじめに

iOS16からSwiftUIのNavigationViewが非推奨になるということで、こちらの記事を「Migrating to new navigation type」👇を読んでまとめてみました。

https://developer.apple.com/documentation/swiftui/migrating-to-new-navigation-types


# 環境
Xcode 14.0

# 内容

### ナビゲーションViewを更新する

非推奨の[`NavigationView`](https://developer.apple.com/documentation/swiftui/navigationview)は

`struct NavigationStack<Data, Root> where Root : View` へ更新する

https://developer.apple.com/documentation/swiftui/navigationstack

:::note warn
非推奨
```swift
NavigationView { // This is deprecated.
    /* content */
}
.navigationViewStyle(.stack)
```
:::

👇

:::note info
iOS16~ 推奨
```swift
NavigationStack {
    /* content */
}
```
:::

### 複数列のナビゲーションViewを更新する
複数列のナビゲーションViewは`NavigationSplitView`を使用する

https://developer.apple.com/documentation/swiftui/navigationsplitview

#### 2列の場合

<img width="200" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/93df580c-f665-f9f0-0d30-2a9dc3067f05.png"> <img width="200" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/9f979da0-84f8-7254-b7ab-ec1ec3057656.png">


:::note warn
非推奨
```swift
NavigationView { // This is deprecated.
    /* column 1 */
    /* column 2 */
}
```
:::

👇

:::note info
iOS16~ 推奨
```swift
NavigationSplitView {
    /* column 1 */
} detail: {
    /* column 2 */
}
```
:::

#### 3列の場合

<img width="250" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/173ce761-8cbf-097d-5807-d687a2bf78b1.png"> <img width="250" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/27295815-77b5-a902-46f6-1f7b7f58dfbc.png">

:::note warn
非推奨
```swift
NavigationView { // This is deprecated.
    /* column 1 */
    /* column 2 */
    /* column 3 */
}
```
:::

👇

:::note info
iOS16~ 推奨
```swift
NavigationSplitView {
    /* column 1 */
} content: {
    /* column 2 */
} detail: {
    /* column 3 */
}
```
:::


### `isActive`を使ったナビゲーションを更新する

非推奨となったNavigationLinkの[`init(_:destination:isActive:)`](https://developer.apple.com/documentation/swiftui/navigationlink/init(_:destination:isactive:)-3v44)は

NavigationStackの[`init(path:root:)`](https://developer.apple.com/documentation/swiftui/navigationstack/init(path:root:)-63x0h)と NavigationLinkの[`navigationDestination(for:destination:)`](https://developer.apple.com/documentation/swiftui/view/navigationdestination(for:destination:)) へ更新する



<img width="100" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/60adab09-bbb8-a8fa-fb51-48ae68d93058.png">  <img width="300" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/5ffe7849-4e0e-238c-1010-683342e892fb.png">


:::note warn
非推奨
```swift
@State private var isShowingPurple = false
@State private var isShowingPink = false
@State private var isShowingOrange = false

var body: some View {
    NavigationView { // This is deprecated.
        List {
            NavigationLink("Purple", isActive: $isShowingPurple) {
                ColorDetail(color: .purple)
            }
            NavigationLink("Pink", isActive: $isShowingPink) {
                ColorDetail(color: .pink)
            }
            NavigationLink("Orange", isActive: $isShowingOrange) {
                ColorDetail(color: .orange)
            }
        }
    }
    .navigationViewStyle(.stack) 
}
```
:::

👇

:::note info
iOS16~ 推奨
```swift
@State private var path: [Color] = [] // Nothing on the stack by default.

var body: some View {
    NavigationStack(path: $path) {
        List {
            NavigationLink("Purple", value: .purple)
            NavigationLink("Pink", value: .pink)
            NavigationLink("Orange", value: .orange)
        }
        .navigationDestination(for: Color.self) { color in
            ColorDetail(color: color)
        }
    }
}
```
:::

### `selection`を使ったナビゲーションを更新

非推奨となったNavigationLinkの[`init(destination:tag:selection:label:)`](https://developer.apple.com/documentation/swiftui/navigationlink/init(destination:tag:selection:label:))は

NavigationSplitViewの[`init(sidebar:detail:)`](https://developer.apple.com/documentation/swiftui/navigationsplitview/init(sidebar:detail:))と NavigationLinkの [`init(_:value:)`](https://developer.apple.com/documentation/swiftui/navigationlink/init(_:value:)-9ziux)[(`init(value:label:)`)](https://developer.apple.com/documentation/swiftui/navigationlink/init(value:label:)-3qb8y) で更新する

<img width="100" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/366b4779-610f-a743-1165-a9ccacbdbf9b.png">  <img width="300" alt="" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631585/e9e0c47a-98d5-fd85-5d1c-01c9fe6fa021.png">


:::note warn
非推奨
```swift
let colors: [Color] = [.purple, .pink, .orange]
@State private var selection: Color? = nil // Nothing selected by default.

var body: some View {
    NavigationView { // This is deprecated.
        List {
            ForEach(colors, id: \.self) { color in
                NavigationLink(color.description, tag: color, selection: $selection) {
                    ColorDetail(color: color)
                }
            }
        }
        Text("Pick a color")
    }
}
```
:::

👇

:::note info
iOS16~ 推奨
```swift
var body: some View {
    NavigationSplitView {
        List(colors, id: \.self, selection: $selection) { color in
            NavigationLink(color.description, value: color)
        }
    } detail: {
        if let color = selection {
            ColorDetail(color: color)
        } else {
            Text("Pick a color")
        }
    }
}
```
:::

# おわりに

iOS16からディープリンクの実装が簡単になったと聞いておりましたが、たしかにそんな感じがしました。引き続き調べていきたいと思います。


# 参考

https://developer.apple.com/documentation/swiftui/migrating-to-new-navigation-types