高校倫理1434987 views
中学数学622001 views
高校国語786245 views
世界の国561479 views
いろは2993462 views
教育149067 views
雑学1472898 views
MathPython493120 views
中学理科1627564 views
高校物理158628 views

値ベースのナビゲーション(navigationDestination)

iOS 16 で導入された値ベースのナビゲーションは、navigationDestination を使ってデータの型に基づいた画面遷移を実現します。従来の NavigationLink よりも柔軟で、プログラム的な制御が容易になりました。

従来の NavigationLink との違い

従来の方法では、NavigationLink に直接遷移先のビューを指定していました。

// 従来の方法
NavigationLink("詳細") {
    DetailView(item: item)
}

値ベースのナビゲーションでは、NavigationLink に値を渡し、その値の型に対応する遷移先を navigationDestination で定義します。

// 値ベースの方法
NavigationLink("詳細", value: item)

// 別の場所で遷移先を定義
.navigationDestination(for: Item.self) { item in
    DetailView(item: item)
}

基本的な使い方

struct Item: Identifiable, Hashable {
    let id = UUID()
    var name: String
}

struct ContentView: View {
    let items = [
        Item(name: "りんご"),
        Item(name: "みかん"),
        Item(name: "バナナ")
    ]
    
    var body: some View {
        NavigationStack {
            List(items) { item in
                NavigationLink(item.name, value: item)
            }
            .navigationDestination(for: Item.self) { item in
                Text("\(item.name)の詳細画面")
                    .navigationTitle(item.name)
            }
            .navigationTitle("フルーツ")
        }
    }
}

値の型は Hashable に準拠している必要があります。

複数の型に対応

異なる型に対して、それぞれ異なる遷移先を定義できます。

struct User: Hashable {
    var name: String
}

struct Product: Hashable {
    var title: String
}

struct ContentView: View {
    var body: some View {
        NavigationStack {
            List {
                Section("ユーザー") {
                    NavigationLink("田中太郎", value: User(name: "田中太郎"))
                    NavigationLink("山田花子", value: User(name: "山田花子"))
                }
                
                Section("商品") {
                    NavigationLink("iPhone", value: Product(title: "iPhone"))
                    NavigationLink("MacBook", value: Product(title: "MacBook"))
                }
            }
            .navigationDestination(for: User.self) { user in
                UserDetailView(user: user)
            }
            .navigationDestination(for: Product.self) { product in
                ProductDetailView(product: product)
            }
        }
    }
}
型による分岐

navigationDestination は型ごとに定義できるため、同じリスト内で異なる種類のデータを扱える。

Hashable 必須

値として渡す型は Hashable に準拠している必要がある。Identifiable だけでは不十分。

遅延評価

遷移が実際に発生するまで、遷移先のビューは生成されない。

列挙型を使ったパターン

画面遷移のパターンを列挙型で定義すると、管理しやすくなります。

enum Destination: Hashable {
    case settings
    case profile(userId: Int)
    case article(articleId: Int)
}

struct ContentView: View {
    var body: some View {
        NavigationStack {
            List {
                NavigationLink("設定", value: Destination.settings)
                NavigationLink("プロフィール", value: Destination.profile(userId: 123))
                NavigationLink("記事", value: Destination.article(articleId: 456))
            }
            .navigationDestination(for: Destination.self) { destination in
                switch destination {
                case .settings:
                    SettingsView()
                case .profile(let userId):
                    ProfileView(userId: userId)
                case .article(let articleId):
                    ArticleView(articleId: articleId)
                }
            }
        }
    }
}
従来の NavigationLink

遷移先を直接指定。シンプルだが、プログラム制御が難しい。

値ベースのナビゲーション

値を渡して型で遷移先を決定。path による制御が可能。

値ベースのナビゲーションは、複雑なナビゲーション構造を持つアプリで特に威力を発揮します。次の記事では、path を使ったプログラム的な画面遷移について解説します。