SwiftUI 官方文檔
SwiftUI 源碼教程
GitHub Package 論壇
前言:最近跟著SwiftUI 源碼教程基本跑了一遍割疾。自己并嘗試寫一些基本的語法或小功能,在寫SwiftUI
時,要嘗試拋開Objective-C
的思想婶肩,兩者完全不同的概念,SwiftUI
多協(xié)議囤热,此View
非彼View
昙啄,只有碼的過程中才會深有感觸...
靜態(tài)TabView
導航視圖便于我們創(chuàng)建分層的視圖堆棧穆役,方便用戶能夠向下獲取數(shù)據(jù),但對于顯示不相關的數(shù)據(jù)而言效果不佳跟衅。為此孵睬,我們需要使用SwiftUI
的TabView
,它會在屏幕底部創(chuàng)建一個按鈕條伶跷,點擊每個按鈕會顯示一個不同的視圖掰读。
1、將選項卡放置在TabView中叭莫,通過tabItem()
修飾符, 可以自定義視圖在選項卡欄中的顯示方式蹈集,從而在其旁邊提供圖像和一些文本:
TabView {
Text("Tab 1")
.tabItem {
Image(systemName: "star")
// Image("homepageSelect" )
Text("Homepages")
}
Text("Tab 2")
.tabItem {
Image(systemName: "star.fill")
Text("My Parcels")
}
}
除了讓用戶通過點擊其標簽項來切換視圖之外,SwiftUI
還允許我們使用狀態(tài)以編程方式控制當前視圖雇初。操作步驟如下:
- 創(chuàng)建一個
@State
屬性以跟蹤當前顯示的選項卡拢肆; - 每當我們想跳到另一個選項卡時,將該屬性修改為一個新值靖诗;
- 將其作為綁定傳遞到
TabView
中郭怪,因此將自動對其進行跟蹤; - 告訴
SwiftUI
應該為該屬性的每個值顯示哪個選項卡刊橘。
第一鄙才、我們需要某種狀態(tài)來跟蹤當前選項卡,因此將其作為屬性添加到ContentView
:
@State private var selectedTab = 0
第二促绵、我們需在某處進行修改時攒庵,這將要求SwiftUI
切換選項卡。我們可以將onTapGesture()
修飾符附加到第一個選項卡败晴,如下所示:
TabView {
.onTapGesture {
self.selectedTab = 1
}
Text("Homepages ")
.tabItem {
Image(systemName: "star")
// Image("homepageSelect" )
Text("Homepages")
}
第三浓冒、我們需要將TabView
的選擇綁定到$selectedTab
。當我們創(chuàng)建TabView
時尖坤,它將作為參數(shù)傳遞稳懒,因此將你的代碼更新為:
TabView (selection: $selectedTab) {...}
當我們說self.selectedTab = 1
時,SwiftUI
如何知道Tab1
是哪個Tab
慢味?你可能會認為這些Tab
可以被視為一個數(shù)組僚祷,在這種情況下,第二個Tab
將位于索引1處贮缕,但這會引起各種問題:如果我們將該 Tab
移至Tab
視圖中的其他位置辙谜,該怎么辦?
在更深層次上感昼,它還分解了SwiftUI
的核心概念之一:我們應該能夠自由地組合視圖装哆。如果Tab 1
是數(shù)組中的第二項,則:
-
Tab 0
是第一個tab。 -
Tab 1
是第二個tab蜕琴。 -
Tab 0
具有顯示Tab 1
的onTapGesture()
萍桌。
對于Tab 0
對如何配置其父項TabView
具有深入的了解。SwiftUI
提供了更好的解決方案:我們可以為每個視圖附加一個唯一的標識符凌简,并將其用于選定的標簽上炎。這些標識符稱為標簽,并使用tag()
修飾符附加雏搂,如下所示:
TabView (selection: $selectedTab) {
HomePageView()
.font(.title/)
.onTapGesture {
self.selectedTab = 1
}
.tabItem {
Image(self.selectedTab == 0 ? "homepageSelected" : "homepage")
// .frame(width: 50, height: 50, alignment: .center)
Text("Homepages")
}
.tag(0)
// MyPacelsView()
.tabItem {
Image(self.selectedTab == 1 ? "parclesSelect" : "parcles")
Text("My Parcels")
}
.tag(1)
}
現(xiàn)在我們可以在選項卡之間來回切換藕施。
當然,僅使用0和1是不理想的——這些值是固定的凸郑,因此可以解決視圖四處移動的問題裳食,但它們不容易記住。所幸的是我們可以改用字符串:給每個視圖有且只有唯一且反映其目的的字符串標記芙沥,然后將其用于@State
屬性诲祸。從長遠來看,這更容易使用而昨,對比整數(shù)更建議使用救氯。
提示:通常要同時使用NavigationView
和TabView
,但要注意:TabView
Tex parse error!NavigationView
, 而不是相反歌憨。
動態(tài)TabView
邏輯與靜態(tài)TabView
一樣 径密,這里我就直接上代碼。如下:
import SwiftUI
struct HomePageView: View {
var body: some View {
VStack {
Image("homepage")
Text("wkk ")
.font(.system(size: 50))
}
}
}
struct MyParclesView: View {
var body: some View {
VStack {
Image("parcles")
Text("My Parcels")
.font(.system(size: 50))
}
}
}
struct TabElement {
var id: Int
var title: String
var image: String
var imageSelect: String
}
let itemList: [TabElement] = [
TabElement(id: 0, title: "Homepages", image: "homepage", imageSelect: "homepageSelected"),
TabElement(id: 1, title: "My Parcels", image: "parcles", imageSelect: "parclesSelect"),
TabElement(id: 2, title: "Booking", image: "booking", imageSelect: "bookingSelect"),
TabElement(id: 3, title: "Me", image: "me", imageSelect: "meSelect"),
]
struct ContentView: View {
@State private var selectedTab = 0
var body: some View {
NavigationView {
VStack {
TabView(selection: $selectedTab) {
ForEach(itemList, id: \.id) { i in
self.viewForTab(i)
}
}
}
}
}
private func viewForTab(_ item: TabElement) -> some View {
// print(item.title)
return contentForTab(item)
.tabItem {
Image(self.selectedTab == item.id ? item.imageSelect: item.image)
Text((self.selectedTab == 0 && item.id == 0) ? "" : item.title)
}.tag(item.id)
}
private func contentForTab(_ item: TabElement) -> some View {
switch item.id {
case 0:
return AnyView(HomePageView())
case 1:
return AnyView(MyParclesView())
default:
return AnyView(HomePageView())
}
}
// 用于打印log
func log(_ log: String) -> EmptyView {
print("** \(log)")
return EmptyView()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
注意:
每個TabView
遍歷對應的content躺孝,需要AnyView()
達到類型擦除視圖。但是AnyView
可能會存在性能問題底桂。他先銷毀就hierarchy
,然后創(chuàng)建新的植袍。這個開銷可能會造成性能的損失。應該有相關優(yōu)化的方案~~~
總結
考慮到TabView的內(nèi)容常規(guī)是4個籽懦,所以用SwiftUI
寫沒必要設置成動態(tài)的TabView
于个,靜態(tài)TabView
就滿足大部分APP了,并且TabView
對應幾個content就定義幾個func
暮顺,條理也清晰厅篓。