使用 enum 當 NavigationLink 的 value
使用 NavigationLink 搭配 value 切換頁面時,value 通常是字串、數字或自訂型別的 struct 資料,不過有時我們也會看到使用 enum 當 NavigationLink 的 value,比方以下兩種應用。
- 使用 enum 定義選單。
- 使用搭配 associated value 的 enum 定義不同類型的資料, associated value 是資料的 id。
接下來我們舉一個簡單的小遊戲 App 當例子。
玩家打開 App 後可選擇要玩二十一點、Uno 或西洋棋,因此我們用 enum Game 定義三種遊戲。
enum Game: CaseIterable, Identifiable {
case blackjack
case uno
case chess
var id: Game { self }
}
enum Game 必須要 Hashable 才能當 NavigationLink 的 value,不過我們不用擔心,因為它沒有 associated value,所以它會自動遵從 Hashable。
在 ContentView 定義遊戲的選擇畫面,透過 navigationDestination 判斷 Game 的類型顯示對應的遊戲畫面。
struct ContentView: View {
var body: some View {
NavigationStack {
HStack {
ForEach(Game.allCases) { game in
NavigationLink(value: game) {
VStack {
Image(game.image)
.resizable()
.scaledToFit()
.frame(width: 100)
Text(game.name)
}
}
}
}
.navigationDestination(for: Game.self) { game in
switch game {
case .blackjack:
BlackjackView()
case .uno:
UnoView()
case .chess:
ChessView()
}
}
}
}
}
Apple 的官方範例也有許多用 enum 當 NavigationLink value 的例子,例如 Backyard Birds & Food Truck。
- Backyard Birds。
使用 enum 定義側選單的選項。
enum AppScreen: Codable, Hashable, Identifiable, CaseIterable {
case backyards
case birds
case plants
case account
var id: AppScreen { self }
}
- Food Truck。
使用 enum 定義主選單的選項。
enum Panel: Hashable {
/// The value for the ``TruckView``.
case truck
/// The value for the ``SocialFeedView``.
case socialFeed
#if EXTENDED_ALL
/// The value for the ``AccountView``.
case account
#endif
/// The value for the ``OrdersView``.
case orders
/// The value for the ``SalesHistoryView``.
case salesHistory
/// The value for the ``DonutGallery``.
case donuts
/// The value for the ``DonutEditor``.
case donutEditor
/// The value for the ``TopFiveDonutsView``.
case topFive
/// The value for the ``CityView``.
case city(City.ID)
}
至於另外一種應用,使用搭配 associated value 的 enum 則會更複雜一點,有興趣的朋友可參考 Apple 的 Destination Video 範例。
使用 enum 定義 category & video,搭配 category & video 的 id 當 associated value。
enum NavigationNode: Equatable, Hashable, Identifiable {
case category(Int)
case video(Int)
var id: Int {
switch self {
case .category(let id): id
case .video(let id): id
}
}
}