SwiftUI 實現(xiàn)靜態(tài)&動態(tài)TabView

SwiftUI 官方文檔
SwiftUI 源碼教程
GitHub Package 論壇


前言:最近跟著SwiftUI 源碼教程基本跑了一遍割疾。自己并嘗試寫一些基本的語法或小功能,在寫SwiftUI時,要嘗試拋開Objective-C的思想婶肩,兩者完全不同的概念,SwiftUI多協(xié)議囤热,此View非彼View昙啄,只有碼的過程中才會深有感觸...

靜態(tài)TabView

導航視圖便于我們創(chuàng)建分層的視圖堆棧穆役,方便用戶能夠向下獲取數(shù)據(jù),但對于顯示不相關的數(shù)據(jù)而言效果不佳跟衅。為此孵睬,我們需要使用SwiftUITabView,它會在屏幕底部創(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 1onTapGesture()萍桌。

對于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)在我們可以在選項卡之間來回切換藕施。

當然,僅使用01是不理想的——這些值是固定的凸郑,因此可以解決視圖四處移動的問題裳食,但它們不容易記住。所幸的是我們可以改用字符串:給每個視圖有且只有唯一且反映其目的的字符串標記芙沥,然后將其用于@State屬性诲祸。從長遠來看,這更容易使用而昨,對比整數(shù)更建議使用救氯。

提示:通常要同時使用NavigationViewTabView,但要注意:TabViewTex 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暮顺,條理也清晰厅篓。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市捶码,隨后出現(xiàn)的幾起案子羽氮,更是在濱河造成了極大的恐慌,老刑警劉巖惫恼,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件档押,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機令宿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門叼耙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人粒没,你說我怎么就攤上這事筛婉。” “怎么了癞松?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵爽撒,是天一觀的道長。 經(jīng)常有香客問我拦惋,道長匆浙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任厕妖,我火速辦了婚禮首尼,結果婚禮上,老公的妹妹穿的比我還像新娘言秸。我一直安慰自己软能,他們只是感情好,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布举畸。 她就那樣靜靜地躺著查排,像睡著了一般。 火紅的嫁衣襯著肌膚如雪抄沮。 梳的紋絲不亂的頭發(fā)上跋核,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機與錄音叛买,去河邊找鬼砂代。 笑死,一個胖子當著我的面吹牛率挣,可吹牛的內(nèi)容都是我干的刻伊。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼椒功,長吁一口氣:“原來是場噩夢啊……” “哼捶箱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起动漾,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤丁屎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后旱眯,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悦屏,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡节沦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了础爬。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片甫贯。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖看蚜,靈堂內(nèi)的尸體忽然破棺而出叫搁,到底是詐尸還是另有隱情,我是刑警寧澤供炎,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布渴逻,位于F島的核電站,受9級特大地震影響音诫,放射性物質(zhì)發(fā)生泄漏惨奕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一竭钝、第九天 我趴在偏房一處隱蔽的房頂上張望梨撞。 院中可真熱鬧,春花似錦香罐、人聲如沸卧波。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽港粱。三九已至,卻和暖如春旦签,著一層夾襖步出監(jiān)牢的瞬間查坪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工宁炫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留偿曙,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓淋淀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親覆醇。 傳聞我的和親對象是個殘疾皇子朵纷,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容