【SwiftUI】NavigationViewの基本的な使い方(前編)

前回に引き続き、アプリに使用した技術をアウトプットしていきます。
解説する私のアプリはこちら。
[わかりすと -勉強サポートアプリ-](https://apps.apple.com/jp/app/id1553876980)

# NavigationView
階層的な画面遷移を管理するビュー。

[公式リファレンス](https://developer.apple.com/documentation/swiftui/navigationview)

# NavigationLink
NavigationView内で、__画面遷移を行うトリガーになるビュー__と__遷移先のビュー__の両方を指定できるビュー。NavigationViewとセットで使う。

[公式リファレンス](https://developer.apple.com/documentation/swiftui/navigationlink)

# 実際の動作

※拡大推奨
<iframe width="560" height="315" src="https://www.youtube.com/embed/57ae8IfOBsU" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

__動画のポイント__

- NavigationViewの外側の領域は切り替わらず、遷移先にも表示される。（動画内のヘルプボタン）
- 遷移先の画面の左上には、前の画面にもどるためのボタンが表示される。
- もどるボタンにはタイトルがそのまま書かれる。

# コード

今回作成したサンプルアプリのソースコードは[こちら](https://github.com/masayoshi0327/NavigationView)

まず、一番上の階層から見ていきましょう。

```Swift:ContentView.swift
import SwiftUI

struct ContentView: View {
    
    let regions = ["カントー地方", "ジョウト地方", "ホウエン地方", "シンオウ地方"]
    
    var body: some View {
        VStack{
            // ここから
            HStack{
                Spacer()
                Button(action: {}, label: {
                    Text("ヘルプ")
                })
            }
            .padding(.horizontal)
            // ここまではNavigationViewに含まれない
            
            //ここから
            NavigationView {
                List(0..<4) { n in
                    NavigationLink(regions[n], destination: Region(id: n, regionName: regions[n]))
                }
                .navigationTitle("そらをとぶ")
            }
            //ここまでがNavigationViewの領域
        }
    }
}
```

基本として、__遷移する（切り替わる）のはNavigationViewの{}内の要素だけ__です。上のソースコードの「ヘルプ」というラベルのボタンはNavigationViewに含まれないため、リンクをタップしても切り替わらずに画面上部に残っています（動画を確認してください）。今回の「ヘルプ」ボタンのように、__何らかの理由で遷移先にもずっと表示させたいものがある場合はNavigationViewに含めない方が良いでしょう__。

次にNavigationViewの中を見ていきます。

NavigationViewの中にはNavigationLinkが書かれており、Listの繰り返し処理で4つ並ぶようにしています。上で説明したとおり、__NavigationLinkは画面遷移のトリガーと遷移先のビューを指定できます__。今回は```regions[n]```（配列regionsのn番目の要素）がトリガー、```Regionビュー```が遷移先となっています。

Regionビューのソースコードはこちら。

```Swift:Region.swift
import SwiftUI

struct Region: View {
    
    let id: Int //地方によって表示を変えるためのプロパティ
    let regionName: String //地方の名前をタイトルにするためのプロパティ
    
    var body: some View {
        //NavigationViewは書かない
        List(0..<4) { n in
            NavigationLink(regionsArray[id][n], destination: Flight(city: regionsArray[id][n]))
                .navigationTitle(regionName)
        }
    }
}

//各地方ごとのデータ
let kanto = ["マサラタウン", "トキワシティ", "ニビシティ", "ハナダシティ"]
let joto = ["ワカバタウン", "ヨシノシティ", "キキョウシティ", "ヒワダタウン"]
let hoen = ["ミシロタウン", "コトキタウン", "トウカシティ", "カナズミシティ"]
let shino = ["フタバタウン", "マサゴタウン", "クロガネシティ", "コトブキシティ"]

//idに対応する配列を取り出すための配列
let regionsArray = [kanto, joto, hoen, shino]
```

ここで見てほしいのは、NavigationLinkはあるのにNavigationViewの記述がどこにも書かれていないことです。NavigationViewは一番上の階層となるビューに書くだけで、遷移先にも機能を持たせることができます。

逆に、下の階層にもNavigationViewを書き、次の画面に遷移するとこのようになります。

![スクリーンショット 2021-02-26 14.06.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1130636/dfc6fa5c-c8ca-408f-4eda-dfad5a3f9f77.png)

画面左上に、前の画面にもどるためのボタンが2つ並んでいることがわかると思います。これはNavigationViewの中にNavigationViewを作っていると判断された結果です。このような表示にしたい場合は別ですが、基本は__一番上の階層にのみNavigationViewを書くことをおすすめします__。

次回はnavigationTitleについて書きます。

# 参考文献

[SwiftUI徹底入門　金田浩明(著)](https://www.amazon.co.jp/SwiftUI-%E5%BE%B9%E5%BA%95%E5%85%A5%E9%96%80-%E9%87%91%E7%94%B0-%E6%B5%A9%E6%98%8E/dp/4815604061/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=SwiftUI+%E5%BE%B9%E5%BA%95%E5%85%A5%E9%96%80&qid=1614007741&sr=8-1)(【注意】Xcode12非対応のものです)