
If you're trying to achieve, there will be roadblocks. I've had them; everybody has had them. But obstacles don't have to stop you. If you run into a wall, don't turn around and give up. Figure out how to climb it, go through it, or work around it.
- Michael Jordan
「標籤列」( Tab Bar )是在螢幕底部的一列持續可見的按鈕,其作為開啟App 不同功能的導覽元件,儘管它曾經被認為在主流 UI 設計中不突出,但標籤列最近又重新流行起來。
在大螢幕裝置出現之前,只有 3.5 吋及 4 吋規格的 iPhone,而使用標籤列的一個缺點是它們占用寶貴的螢幕空間,這對於小螢幕來說,尤其具有挑戰性。然而,在 2014 年底推出大螢幕尺寸的iPhone 6 及iPhone 6 Plus 之後,App 開發者開始用標籤列取代現有的選單。著名的 App 如 Facebook、Whatsapp、Twitter、Quora、Instagram 及 Apple Music,都轉向了標籤列導覽。
標籤列的優點是允許使用者只要點擊一下,即可訪問 App 的核心功能,儘管它們占用了螢幕空間,但權衡之下被認為是值得的。
導覽控制器藉由管理一堆視圖控制器來幫助分層內容導覽,而標籤列管理多個不一定具有直接關係的視圖控制器。通常標籤列控制器至少包含二個標籤,你可按照 App 的需求增加最多五個標籤。

我在上一章中介紹過 TabView,但是我們將它設定為頁面滾動視圖。在本章中,我們將使用它來建立一個如圖21.1 所示的標準標籤介面。我們將建立具有三個項目的標籤列:
在開發導引視圖時,我們將 TabView 設定為使用 PageTabViewStyle,如下所示:
TabView {
.
.
.
}
.tabViewStyle(.page(indexDisplayMode: .always))
這將建立一個允許使用者可在不同頁面之間導覽的頁面滾動視圖。要建立標準標籤視圖,只需省略 .tabViewStyle 修飾器並使用預設樣式。以下是一個例子:
TabView {
Text("Discover")
.tabItem {
Label("Discover", systemImage: "wand.and.rays")
}
.tag(1)
Text("About")
.tabItem {
Label("About", systemImage: "square.stack")
}
.tag(2)
}
上列的程式碼建立了一個標準標籤介面,其中一個標籤列顯示兩個標籤項目。
對於我們的 FoodPin 專案,我們將建立一個單獨檔案來存放標籤介面。在專案導覽器中的「View」資料夾上按右鍵,並選擇「New File...」,然後選取「SwiftUI View」模板, 將檔案命名為「MainView.swift」。
在 MainView 結構中,宣告一個狀態變數來存放目前的標籤索引:
@State private var selectedTabIndex = 0
然後更新 body 視圖如下:
TabView(selection: $selectedTabIndex) {
RestaurantListView()
.tabItem {
Label("Favorites", systemImage: "tag.fill")
}
.tag(0)
Text("Discover")
.tabItem {
Label("Discover", systemImage: "wand.and.rays")
}
.tag(1)
Text("About")
.tabItem {
Label("About", systemImage: "square.stack")
}
.tag(2)
}
我們在標籤視圖中有三個標籤,第一個標籤是 RestaurantListView,而其他兩個標籤是 Text 視圖。要建立標籤列UI,我們將三個子視圖包裹在一個 TabView 中,對於每個視圖,我們使用 tabItem 修飾器來指定名稱與圖片。系統圖片是來自於內建的 SF Symbols。
在接下來的章節中,我們會實作 Discover 與 About 視圖,現在我們將它們保持為一個簡單的文字視圖。進行這些更改後,在預覽窗格中執行 App,你應該能夠與標籤列進行互動,如圖 21.2 所示。

動作標籤項目的顏色是黑色,這是因為我們沒有為標籤視圖指定主色。要變更動作標籤列項目的顏色,則將 .tint 修飾器加到 TabView:
.tint(Color("NavigationBarTitle"))
嘗試再次測試 App,當你導覽到細節視圖時,標籤列現在應該會消失,如圖 21.3 所示。

假設你已經正確實作所有的程式碼更改,你應該能夠在預覽窗格中預覽 MainView。然而,如果你在模擬器中執行 App,則只會載入 RestaurantListView,因為它被設定為 App 的初始視圖。
要更改它的話,開啟 FoodPinApp.swift 並更新body 如下:
var body: some Scene {
WindowGroup {
MainView()
}
.modelContainer(for: Restaurant.self)
}
這是你設定 App 的初始視圖的地方。當你將 RestaurantListView 更改為 MainView,再次於任何模擬器上執行這個App,App 應該會載入 MainView 而不是 RestaurantListView 了。
到目前為止,你應該充分了解如何建立基於標籤列的使用者介面,並加入新的標籤列項目。如你所見,SwiftUI 簡化了在標籤視圖中嵌入視圖的過程,使其實現起來非常簡單。
使用 SwiftUI,您可以彈性地自訂標籤視圖的外觀和行為,進而打造具有吸引力且直覺的使用者介面。無論你是想顯示 App 的不同功能、呈現分層內容、還是提供對基本功能的快速訪問,SwiftUI 的標籤視圖都提供了方便且有效率的解決方案。
透過利用至目前為止所介紹的觀念與技術,您將具備在SwiftUI App 中實作基於標籤的導覽的所需知識及工具,為使用者提供無縫且愉快的體驗。
在本章所準備的範例檔中,有最後完整的Xcode 專案可供你下載參考:http://www.appcoda.com/resources/swift59/swiftui-foodpin-tabview.zip 。