プログラム的な画面遷移(path)

NavigationStack の path パラメータを使うと、ナビゲーション履歴をプログラムから制御できます。ボタンタップで任意の画面に遷移したり、一気にルートに戻ったりする機能を実装できます。

NavigationPath の基本

NavigationPath はナビゲーション履歴を保持するデータ構造です。

struct ContentView: View {
    @State private var path = NavigationPath()
    
    var body: some View {
        NavigationStack(path: $path) {
            VStack {
                Button("画面Aへ") {
                    path.append("A")
                }
            }
            .navigationDestination(for: String.self) { value in
                Text("画面 \(value)")
            }
        }
    }
}

path.append() で値を追加すると、その値に対応する画面に遷移します。

複数画面への遷移

path に複数の値を追加すると、一度に複数階層を進むことができます。

struct ContentView: View {
    @State private var path = NavigationPath()
    
    var body: some View {
        NavigationStack(path: $path) {
            VStack(spacing: 20) {
                Button("画面Aへ") {
                    path.append("A")
                }
                
                Button("A → B → C へ一気に遷移") {
                    path.append("A")
                    path.append("B")
                    path.append("C")
                }
            }
            .navigationDestination(for: String.self) { value in
                VStack {
                    Text("画面 \(value)")
                    Text("階層: \(path.count)")
                }
            }
            .navigationTitle("ホーム")
        }
    }
}

ルートに戻る

path を空にするとルート画面に戻ります。

struct DetailView: View {
    @Binding var path: NavigationPath
    
    var body: some View {
        VStack {
            Text("詳細画面")
            
            Button("ホームに戻る") {
                path.removeLast(path.count)  // すべて削除
            }
            
            Button("1つ戻る") {
                path.removeLast()  // 1つ削除
            }
        }
    }
}
path.append(value)

ナビゲーションスタックに値を追加し、対応する画面に遷移する

path.removeLast()

最後に追加された画面を削除し、1つ前の画面に戻る

path.removeLast(k)

k 個の画面を削除する。path.count を渡すとルートに戻る

型安全な path

NavigationPath は異なる型を混在させることができますが、単一の型だけを扱う場合は型付き配列を使う方が安全です。

struct ContentView: View {
    @State private var path: [String] = []  // String のみを扱う
    
    var body: some View {
        NavigationStack(path: $path) {
            List {
                NavigationLink("詳細", value: "detail")
            }
            .navigationDestination(for: String.self) { value in
                Text(value)
            }
        }
    }
}

実践例:ウィザード形式の画面遷移

enum WizardStep: Hashable {
    case name
    case email
    case confirm
}

struct WizardView: View {
    @State private var path: [WizardStep] = []
    @State private var name = ""
    @State private var email = ""
    
    var body: some View {
        NavigationStack(path: $path) {
            VStack {
                Text("ユーザー登録")
                Button("開始") {
                    path.append(.name)
                }
            }
            .navigationDestination(for: WizardStep.self) { step in
                switch step {
                case .name:
                    NameInputView(name: $name, path: $path)
                case .email:
                    EmailInputView(email: $email, path: $path)
                case .confirm:
                    ConfirmView(name: name, email: email, path: $path)
                }
            }
        }
    }
}

struct ConfirmView: View {
    let name: String
    let email: String
    @Binding var path: [WizardStep]
    
    var body: some View {
        VStack {
            Text("名前: \(name)")
            Text("メール: \(email)")
            
            Button("登録完了") {
                path.removeAll()  // ルートに戻る
            }
        }
    }
}
タップベースの遷移

NavigationLink をタップして遷移。シンプルな画面構成向け。

プログラム的な遷移

path を操作して遷移。ウィザード、条件分岐、ディープリンク向け。

path を使ったプログラム的なナビゲーションにより、従来は難しかった複雑な画面遷移パターンを実装できるようになりました。