旧 NavigationView との違い

iOS 16 で NavigationStack と NavigationSplitView が導入され、従来の NavigationView は非推奨になりました。両者の違いと移行のポイントを解説します。

基本的な置き換え

// 旧: NavigationView
NavigationView {
    List {
        NavigationLink("詳細") {
            DetailView()
        }
    }
}

// 新: NavigationStack
NavigationStack {
    List {
        NavigationLink("詳細") {
            DetailView()
        }
    }
}

シンプルなケースでは、NavigationViewNavigationStack に置き換えるだけで動作します。

主な違い

プログラム的なナビゲーション

NavigationStack は path パラメータでナビゲーション履歴を制御できる。NavigationView ではこれが困難だった。

値ベースの遷移

NavigationStack では navigationDestination で型に基づいた遷移先を定義できる。コードの見通しが良くなる。

iPad/Mac 対応

NavigationView の .columns スタイルは NavigationSplitView に分離された。役割が明確になった。

NavigationLink の変化

// 旧: isActive バインディング
@State private var isActive = false

NavigationLink(isActive: $isActive) {
    DetailView()
} label: {
    Text("詳細")
}

// 新: 値ベースのナビゲーション
@State private var path = NavigationPath()

NavigationStack(path: $path) {
    Button("詳細") {
        path.append("detail")
    }
    .navigationDestination(for: String.self) { value in
        DetailView()
    }
}

スタイル指定の変化

// 旧: NavigationView + navigationViewStyle
NavigationView {
    /* ... */
}
.navigationViewStyle(.columns)

// 新: NavigationSplitView を使用
NavigationSplitView {
    /* サイドバー */
} detail: {
    /* 詳細 */
}
NavigationView + .stack

NavigationStack で置き換え。スタック型のナビゲーション。

NavigationView + .columns

NavigationSplitView で置き換え。マルチカラムレイアウト。

移行時の注意点

旧 API新 API
NavigationViewNavigationStack または NavigationSplitView
NavigationLink(isActive:)NavigationLink(value:) + navigationDestination
NavigationLink(tag:selection:)NavigationLink(value:) + path
.navigationViewStyle(.stack)NavigationStack
.navigationViewStyle(.columns)NavigationSplitView

後方互換性

iOS 15 以前もサポートする必要がある場合は、条件分岐で対応します。

struct ContentView: View {
    var body: some View {
        if #available(iOS 16.0, *) {
            NavigationStack {
                MainList()
            }
        } else {
            NavigationView {
                MainList()
            }
            .navigationViewStyle(.stack)
        }
    }
}

移行のメリット

// NavigationStack の利点: ディープリンクが簡単
struct ContentView: View {
    @State private var path: [Route] = []
    
    var body: some View {
        NavigationStack(path: $path) {
            HomeView()
                .navigationDestination(for: Route.self) { route in
                    destinationView(for: route)
                }
        }
        .onOpenURL { url in
            // URL から path を構築してディープリンク
            if let route = parseURL(url) {
                path = [route]
            }
        }
    }
}

NavigationView では実現が難しかったプログラム的なナビゲーション制御が、NavigationStack では自然に書けるようになりました。新規プロジェクトでは必ず NavigationStack / NavigationSplitView を使用しましょう。