iOS App 程式開發

利用 SwiftUI 元件 大幅簡化 TabView 的管理流程!

利用 SwiftUI 元件 大幅簡化 TabView 的管理流程!
利用 SwiftUI 元件 大幅簡化 TabView 的管理流程!
In: iOS App 程式開發, SwiftUI 框架, UI

本篇原文(標題:How To Build Tab and Split Views in SwiftUI )刊登於作者 Medium,由 Keith Lander 所著,並授權翻譯及轉載。

像 Wikipedia 和 Facebook 這樣多模式 App,會使用 TabBar 介面來讓使用者從不同操作模式中切換,例如 Wikipedia 上有 History、Places、Saved、Search 四個 Tab。一般來說,我們會將 TabBar 與 UITabBarController 物件結合使用,但也可以在 App 中將它們用作獨立控件。TabBar 總是出現在螢幕最底部,並顯示一個或多個 UITabBarItem 物件。

就如你所期待,SwiftUI 大幅地簡化了 TabView 的管理流程。在 WWDC 2019 的 SwiftUI Essentials 演講中介紹了 TabbedView 元件,其底下每個 TabItem 都導向至一個 SplitView。不幸的是,當我發現這項新元件時,Apple 已在 WWDC 之後變更了 TabbedView,也更改了 Tab 的處理方式 ── 他們以 TabView 元件取代 TabbedView。

在這篇文章中,我將分享如何建立一個 TabView,並連結 TabItem 到 SplitView 上。

使用 TabBar 的範例 App

想像一下,你想要建構一個 App 讓使用者記錄家庭旅遊,並記下每次旅遊的細節。同時,你也想讓使用者可以看看到過的地方的照片。以下就是這個 App 的 TabBar:

swiftui-demo-app

我已經為這個 App 建立了一個簡單的 XCode 專案。以下是 ContentView 的程式碼:

struct ContentView: View {
    var body: some View {
        VStack {
            Text(verbatim:"Family Outings")
                .font(.largeTitle)
                .fontWeight(.heavy)
                .foregroundColor(.primary)

            TabView {
                TripsView(trips: trips).tabItem {
                    NavigationLink(destination: TripsView(trips: trips)) {
                        Image(systemName: "car")
                        Text("Trips") }.tag(1)
                }
                PlacesView(places:places).tabItem {
                    NavigationLink(destination: PlacesView(places:places)) {
                        Image(systemName: "photo")
                        Text("Places") }.tag(2)
                }
            }
        }
    }
}

如你所見,這個 ContentView 是由具有兩個視圖的 VStack 所組成:

  • 一個簡單的 Text 視圖,包含了主畫面的標題。
  • 一個有兩個 Tab 的 TabView

看看 TabView 的第一個項目,它是由幾個部分組成的。首先,有個調用 tabitem 呼叫的視圖宣告 TripsView(trips:trips),它的效果是為 TripsView 設定 TabItem。之後,有一個包含 NavigationLink 的閉包,它用來導向目的地 TripsView,而這個 Link 是由 Tab 的圖片及標題組成的。

啟動 App 來顯示 TripsView 的內容。

tripview

App 的預設動作是選擇第一個 TabItem。有一個版本的 TabView 可以讓你指定選擇的項目,不過要注意的是這需要一個 Bindable 物件。

點擊 Places Tab 來顯示地點列表。

placeview

以上就是關於 TabView 的部份。現在讓我們看看到 SplitView 吧!此時,TripViewPlaceView 的程式碼看起來像這樣:

struct TripsView: View {
    var trips: [Trip]
    var body: some View {
        List {
            ForEach(trips) { (trip) in
                Text(trip.id)
            }
        }
    }
}

struct PlacesView: View {
    var places: [Place]
    var body: some View {
        List {
            ForEach(places) { (place) in
                Text(place.id)
            }
        }
    }
}

如你所見,TripViewPlaceView 都是由一個簡單列表組成,從中建立 trips 裡每個元素的實例。假設我們希望能夠看到每個 trip 的細項的話,就需要將 List 包進一個 NavigationView 裡,而且列表裡的每個項目也需要包入在 NavigationLink 裡,像這樣:

struct TripsView: View {
    var trips: [Trip]
    var body: some View {
        NavigationView {
            List {
                ForEach(trips) { (trip) in
                    NavigationLink(destination: TripDetails(trip:trip)) {
                        Text(trip.id)
                    }
                }
            }.navigationBarTitle(Text("Trips"))
        }
    }
}

要注意的是 NavigationBarTitle 修飾符是在 List 的尾端,而不是 NavigationView 的尾端。接著,啟動 App,現在你會看到顯示存在連結的按鈕:

swiftui-demo-app-2

點擊其中一個,就會顯示一個 TripDetails 視圖:

tripdetails

點下返回按鈕,你就會回到 Trip 列表。

範例 App 在 iPad 上的問題

到目前為止,我只使用 iPhone 模擬器來示範。如果使用 iPad 模擬器的話,會是這樣的結果:

swiftui-ipad-demo-1

我想你也看得出問題所在:點擊 Places Tab 後出現的竟是一個空白畫面,這到底是為甚麼呢?當我第一次碰到這個問題時,我以為是某個步驟出錯了,花了我不少的時間才弄清楚原因,原來是 SwiftUI 使用了一個 SplitView!所以我只需要從左滑向右,一個有 Trip 列表的 MasterView 就這樣出現了。點擊其中一個項目,就會顯示在 MasterView 後面的 DetailView。如果你點擊 DetailView,它會蓋過 MasterView。但因為沒有返回按鈕,所以你必須再次向右滑動才能回到上頁。

swiftui-ipad-demo-2

這雖然是可以正確運作,但糟糕的介面設計讓我完全不想釋出這樣的 App。在網路上做了很多資料搜集後,我終於找到解答!所有答案都在文件裡,只是不容易發現。所以,我要做的就只是添加 .navigationViewStyle(StackNavigationViewStyle()NavigationView 裡,這麼一來 App 就會像 iPhone 版本一樣運作,MasterView 會填滿整個視窗畫面,並且當列表上的項目被點選時,DetailView 會滑入進來。

雖然 iPad 的 MasterView 和 DetailView 架構清楚,但我還沒有找到方法來克服這個使用上的問題。不過,我肯定 Apple 很快會找出方法來複製 UISplitView 的 UIKit 版本;但目前來說,我可以接受上面提到的解決方法。

本次教學就到這裡,希望這篇文章可以對使用 SwiftUI 作業的各位有所幫助。

本篇原文(標題:How To Build Tab and Split Views in SwiftUI)刊登於作者 Medium,由 Keith Lander 所著,並授權翻譯及轉載。

作者簡介:Keith Lander,擁有 52 年軟體開發經驗,是 Writing Shed 開發者,Writing Shed 這個 iOS & Mac App 是特別為寫作者而設的。

譯者簡介:楊敦凱-目前於科技公司擔任 iOS Developer,工作之餘開發自有 iOS App 同時關注網路上有趣的新玩意、話題及科技資訊。平時的興趣則是與自身專業無關的歷史、地理、棒球。來信請寄到:[email protected]

作者
AppCoda 編輯團隊
此文章為客座或轉載文章,由作者授權刊登,AppCoda編輯團隊編輯。有關文章詳情,請參考文首或文末的簡介。
評論
更多來自 AppCoda 中文版
很好! 你已成功註冊。
歡迎回來! 你已成功登入。
你已成功訂閱 AppCoda 中文版 電子報。
你的連結已失效。
成功! 請檢查你的電子郵件以獲取用於登入的連結。
好! 你的付費資料已更新。
你的付費方式並未更新。