SwiftUIにおけるNavigationLinkの使用方法


はじめに

NavigationLinkってなに?という方はこちらのドキュメントを参照してください。
簡単に説明するとNavigationLinkを使用することで画面を遷移させる事ができます。
今回記事を書こうと思った経緯はNavigationLinkを使用する際に毎回同じ記事をみてしまい、もうこれは自分で記事を書くまで定着しないなと思い始めたので書きました。
またどうせ書くなら他の記事ではあまり記載がないnavigationTitleやnavigationBarBackButtonの定義する場所による動作の違いみたいなものも試してみたので紹介していきたいと思います。

環境

・ macOS: Monterey
・ Xcode: 13.3
・ iOS: 15.0

実装

シンプルに書いてみる

NavigationView {
    NavigationLink {
        NavigationTestA()
    } label: {
        Text("next testAview")
    }
}

まず適当にNavigationTestAという名前のViewを用意しておきます。
そのViewにNavigationLinkを使用して遷移させるシンプルなコードです。

動作としてはTestAのViewに遷移し、Backボタンをタップで戻ってきます。
御作法についてはNavigationView内に書かなければNavigationLinkで遷移させることはできません。
以下のように書き換えてみます。

VStack {
    NavigationLink {
        NavigationTestA()
    } label: {
        Text("next testAview")
    }
}


グレーになってボタンをタップしても遷移しなくなりました。

遷移画面から更に遷移させる


上のGifのように遷移先から更に遷移させる実装を行なってみます。
例えばHomeViewがスタートのViewとしてAView、BViewと移動させる場合、愚直に書こうとするとHomeView内にNvigationLinkでAviewに遷移させて、Aviewで更にNavigationLinkを使用してBViewに遷移させるので以下のようなコードを書くと思います。

HomeView
NavigationView {
    NavigationLink {
        NavigationTestA()
    } label: {
        Text("next testAview")
    }
}
AView
NavigationView {
    VStack {
        Text("testAView")
        NavigationLink {
            NavigationTestB()
        } label: {
            Text("next textBview")
        }
    }
}

するとこのようにNvagationView内に更にNavigationViewが実装されてしまいます。単に遷移を連続的にしたいのであればAViewでのNavigationView を削除します。すると以下のように動作します。

AView
    VStack {
        Text("testAView")
        NavigationLink {
            NavigationTestB()
        } label: {
            Text("next textBview")
        }
    }


遷移先のBViewも以下のように実装します。

BView
VStack {
   NavigationLink {
       Text("testB")
   } label: {
       Text("next finalView")
   }
}

これで遷移を続けて行うことを試すことができました。
続いてタイトルやBackボタンを自由に変更していきたいと思います。

TitleやButtonをカスタマイズする

Title

NvigationView内にnavigationTitleでタイトルをつけることができます。

NavigationView {
    NavigationLink {
        NavigationTestA()
    } label: {
        Text("next testAview")
    }
    .navigationTitle("HomeView")
}

またnavigationBarTitleDisplayModeでタイトルの大きさと位置を変更することができますが、現状2種類のみです。

コード 表示
.automatic 親Viewで指定されている効果を引き継いで表示する
.large 大きな文字で左詰で表示
.inline 小さな文字でセンターに表示

Button

タイトル横に任意のボタンを配置することも可能です。

NavigationLink {
    NavigationTestA()
        .toolbar {
            ToolbarItem(placement: .navigationBarLeading) {
                Button {
                    
                } label: {
                    Text("右側に表示")
                }

            }
        }
} label: {
    Text("next testAview")
}

.toolbarを使用することで配置することができます。またToolbarItemでnavigationBarLeadingで左側、navigationBarTrailingで右側を指定することができます。
(右側に配置したもの)

デフォルトではTitleでつけた名前がBackボタン名になりますが、これも任意のもにしたい場合AViewに対して.navigationBarBackButtonHidden(true)を付与することでBackボタンを非表示にすることができます。また遷移のトリガーを任意のプロパティで制御したい場合はisActiveで指定します。

NavigationView {
    NavigationLink(isActive: $showView) {
        NavigationTestA()
            .navigationBarBackButtonHidden(true)
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    Button {
                        showView.toggle()
                    } label: {
                        Text("戻る")
                    }

                }
            }
    } label: {
        Text("next testAview")
    }
    .navigationTitle("HomeView")
    .navigationBarTitleDisplayMode(.large)
}

showViewは@State private var showView = falseのように適当にBool型で定義しています。
これで以下のような動きになります。

まとめ

やはり色んな書き方ができる為、逆に迷うことがありますが、記事を書いてみて
・遷移先はdestination
・遷移の判定はisActive
・ボタン自体はLabel
と3つの要素で定義できることが整理できたのでよかったです。
またTitleやBackボタンは遷移先のViewでも親のViewでもどちらでも指定できるのが意外でした。
これでNavigationLinkに関してはほぼマスターできた気がしました^^