【SwiftUI】NavigationStackで画面遷移をコントロールする

未分類

新たに書き直した為、この記事ではなく以下の記事を確認してください。

iOS16/iPadOS16からはNavigationViewが非推奨(Deprecated)となりました。
代わりに実装されたのがNavigationStackです。
これに合わせてNavigationLinkにも変更がありselectionの引数があるものが非推奨になりました。画面遷移を制御するコードが大きく変わったので確認していきましょう。

NavigationStackの画面遷移

NavigationStackの準備

まずは基本となるNavigationStackを用意します。
フルーツの一覧を表示し選択したフルーツの名前が表示される簡単なNavigationStackです。

enum Fruits:String,CaseIterable {
    case apple = "Apple"
    case grape = "Grape"
    case strawberry = "Strawberry"
}

struct FruitsListView: View {
    
    var body: some View {
        NavigationStack{
            List(Fruits.allCases ,id: \.self){ fruit in
                NavigationLink(fruit.rawValue, value: fruit)
            }
            .navigationDestination(for: Fruits.self) { fruit in
                Text(fruit.rawValue)
            }
            .navigationTitle("FruitsList")
        }
    }
}

基本形

NavigationStackで画面遷移するには引数のpathを使います。

まず@Stateでpath用の変数を用意します。
ここはNavigationLinkで使用するvalueの型の『配列』にします。

次にNavigationStackに引数を追加します。Bindingなので先程@Stateで宣言した変数を$つきで渡します。

最後に遷移させるコードです。
配列に遷移先のvalueを追加することで目的の画面に遷移します。
今回は簡単にボタンを用意しました。

struct FruitsListView: View {

    @State private var path: [Fruits] = [] //追加
    
    var body: some View {
        NavigationStack(path: $path){//追加
            List(Fruits.allCases ,id: \.self){ fruit in
                NavigationLink(fruit.rawValue, value: fruit)
            }
            .navigationDestination(for: Fruits.self) { fruit in
                Text(fruit.rawValue)
            }
            .navigationTitle("FruitsList")
            
            //追加
            Button("Apple"){
                path.append(.apple)
            }
        }
    }
}

画面遷移に合わせて配列に追加/削除されるイメージです。
初期値を入れたりonAppearで入れる事で直接遷移先を表示する事も可能ですし、
配列から値を削除することで戻る事も出来ます。

複数回画面遷移する

pathは配列です。配列に複数の値を入れると複数回画面遷移します。
例えば配列が[.apple , .grape]となっていればFruitsList>Apple>Grapeといった形で画面遷移します。
配列の中身がそのまま画面遷移の順と一致する様になっています。

また、配列を空にすると一度にListまで戻る事が出来ます。
配列のindexの小さい要素だけ削除する事もできます。
上記の例であれば.appleのみを削除するとGrape画面からBackを押すとそのままListに戻ります。

struct NavigaitonControlView: View {
    
    @State private var path: [Fruits] = []
    
    var body: some View {
        NavigationStack(path: $path){
            List(Fruits.allCases ,id: \.self){ fruit in
                NavigationLink(fruit.rawValue, value: fruit)
            }
            .navigationDestination(for: Fruits.self) { fruit in
                Text(fruit.rawValue)
                
                Button("Back to List"){//追加
                    path.removeAll()
                    
                }
                
                Button("Remove at 0"){//追加
                    path.remove(at: 0)
                }
            }
            .navigationTitle("FruitsList")
            
            Button("Apple"){
                path.append(.apple)
                path.append(.grape)//追加
            }
        }
    }
}

NavigationViewとの比較

ここまでの内容でNavgationViewとの比較をします。

NavgationViewの場合はNavigationLinkに全て詰め込まれています。
NavigationLinkが長くなりがちで、Viewも別なクラスや関数に分けないとネストが深くなります。

また重要な点として、NavigationViewは1つの変数につき1階層毎の管理となっています。
NavigationStackでは配列で全階層を管理することになります。

複数階層のNavgationを利用する時に大きく差が出てくる点なので注意が必要です。

struct OldNavigationControlView: View {
    
    @State private var selection:Fruits?
    
    var body: some View {
        NavigationView{
            VStack {
                List(Fruits.allCases ,id: \.self){ fruit in
                    NavigationLink(fruit.rawValue, tag: fruit, selection: $selection) {
                        Text(fruit.rawValue)
                        
                        Button("Back to List"){
                            selection = nil
                        }
                    }
                }
                .navigationTitle("FruitsList")
                
                Button("Apple"){
                    selection = .apple
                }
            }
        }
    }
}

最後に

NavigationStackで複数階層を制御する方法は検証やコードを整える作業に時間がかかっています。
長くなると思いますので、後に別記事をして作成しリンク追加します。

追記:以下の続きは記事をご確認ください。

【SwiftUI】NavigationStackで画面遷移をコントロールする(NavigationPath)(複数階層)
新たに書き直した為、この記事ではなく以下の記事を確認してください。 iOS16/iPadOS16以降でNavigationStackが追加されNavigationViewがDeprecatedになりました。合わせてNavigationLin...

コメント

  1. […] […]

タイトルとURLをコピーしました