値ベースのナビゲーション(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 を使ったプログラム的な画面遷移について解説します。