使用 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
}
}
}

--

--

彼得潘的 iOS App Neverland
彼得潘的 Swift iOS App 開發問題解答集

彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,彼得潘的 Swift 程式設計入門,App程式設計入門作者,http://apppeterpan.strikingly.com