QSD的Swift妙妙屋1:TabView

TabView


開(kāi)發(fā)者手冊(cè)

說(shuō)明

TabView is a view that switches between multiple child views using interactive user interface elements.
TabView是一個(gè)使用交互式用戶(hù)界面元素在多個(gè)子視圖之間切換的視圖。

申明

struct TabView<SelectionValue, Content> where SelectionValue : Hashable, Content : View

概述

To create a user interface with tabs, place views in a TabView and apply the [tabItem(_:)] modifier to the contents of each tab. The following creates a tab view with three tabs:

例如以下的代碼

TabView {
    Text("The First Tab")
        .tabItem {
            Image(systemName: "1.square.fill")
            Text("First")
        }
    Text("Another Tab")
        .tabItem {
            Image(systemName: "2.square.fill")
            Text("Second")
        }
    Text("The Last Tab")
        .tabItem {
            Image(systemName: "3.square.fill")
            Text("Third")
        }
}
.font(.headline)

可以創(chuàng)造一個(gè)最基本的TabView

!!!NOTICE

Tab里的內(nèi)容只能包含文字,或圖片,或文字和圖片的組合

Tab一般來(lái)說(shuō)最多只能顯示5個(gè),多余的Tab(包括第5個(gè))會(huì)被省略到一個(gè)...

5個(gè)Tab
6個(gè)Tab

今日目標(biāo)

1. 以L(fǎng)ogo+文字的形式創(chuàng)建5個(gè)TabView

2. 封裝TabView到一個(gè)TabContent的func中,并添加選中Tab能改變Logo樣式的功能

1. 創(chuàng)建5個(gè)TabView

外觀

上面是一個(gè)圖標(biāo),下面是文字,所以才用VStack

以第一個(gè)lightbulb??+'飯乎'為例

VStack{
    Image(systemName: "lightbulb")
    Text("飯乎")
  }

于是得到了一個(gè):

構(gòu)造TabView核心代碼

TabView(selection: $selection){
            VStack{
                Text("現(xiàn)在選中的Tab:\(selection)")
                    .font(.title)
                Button(action: {
                    withAnimation{
                        self.selection = 1
                    }
                })
                {
                    Text("Change Tab to 1")
                        .font(.largeTitle)
                } //用按鈕手動(dòng)切換到第二個(gè)Tab
            }
                .tabItem {
                    VStack{
                        Image(systemName: "lightbulb")
                        Text("飯乎")
                    }
                }
                .tag(0)
// 其他幾個(gè)tab以此類(lèi)推

解釋

selection: $selction用于獲取當(dāng)前選中的Tab編號(hào),也就是最后tag里的值
tag用于給每一個(gè)Tab標(biāo)記一個(gè)獨(dú)特的編號(hào)
systemName是個(gè)好東西,能調(diào)用Apple全套的圖標(biāo)。可以下載SF Symbols查閱圖標(biāo)名稱(chēng)

2. 創(chuàng)造一個(gè)TabContent的func,輸入Tab的編號(hào)、是否選中,并返回some View

先把每個(gè)Tab的名稱(chēng)/圖標(biāo)名稱(chēng)加到Array里

let TabName: Array<String> = ["飯乎","飯廳","飯跡","飯桶","飯具","垃圾桶"]
let TabLogoName: Array<String> = ["lightbulb","tray.full","clock","person.circle","hammer","trash"]

TabContent返回一個(gè)VStack,包含Logo和文字

選中時(shí)更改圖標(biāo):如果選中,就圖標(biāo)名稱(chēng)末尾加上.fill

func TabContent (TabIndex: Int, Selected: Bool) -> some View {
    return
        VStack {
            Image(systemName: Selected ? (TabLogoName[TabIndex] + ".fill"): TabLogoName[TabIndex])
            Text(TabName[TabIndex])
        }
}

解釋

Selected ? (TabLogoName[TabIndex]+".fill"):TabLogoName[TabIndex]
形如XXX ? A : B,如果XXX是真的就返回A,否則返回B

some View

some View的這個(gè)奇怪用法,俺也不是完全懂。
這里有一篇文章仿佛可以參考https://zhuanlan.zhihu.com/p/105213050
some View的用法使得SwiftUI支持接受一些opaque return types——即我們并不需要非常明確的告訴SwiftUI這個(gè)東西是啥,他只要遵循conform View就可以了。
簡(jiǎn)而言之,some View是指,這個(gè)東西長(zhǎng)得像一個(gè)View,遵循View的法則。

因此在SwiftUI的語(yǔ)法下,以下代碼是會(huì)報(bào)錯(cuò)的:

    func WrongExample() -> View {
        return Text("This code is wrong!")
    }

錯(cuò)誤信息:Protocol 'View' can only be used as a generic constraint because it has Self or associated type requirements,這是因?yàn)槊髅魑覀兿胍黵eturn一個(gè)View,但是程序里return了一個(gè)Text!

這樣是正確的代碼;

    func RightExample() -> Text {
        return Text("Ohhhhhhh!")
    }

但是這樣并不是很方便——這個(gè)東西只能return一個(gè)Text,應(yīng)用不是非常廣泛;
因此我們選擇使用some View

    func RightExample() -> some View {
        return Text("Ohhhhhhhh!")
    }
引用斯坦福那位教授的奇妙比喻:
  1. View就像樂(lè)高。
  2. Text就像一塊樂(lè)高——他是樂(lè)高的基本元件之一,他是樂(lè)高。
  3. 把很多樂(lè)高元件組合起來(lái),形成一個(gè)大東西,他還是樂(lè)高。
  4. Lego Bricks -> Lego Furniture -> Lego House -> Lego Neighbourhood -> Lego World!他們都是樂(lè)高。
  5. 和樂(lè)高不同的是,有些特殊的View用來(lái)組合像Text一樣的基本元件,他們叫View Combiner。
  6. 因此,some View也可以返回一些View Combiner,他們之中有很多的View。

然后主程序中調(diào)用下就可以了

最終代碼&運(yùn)行效果


//
//  ContentView.swift
//  WhereToEat?
//
//  Created by QSD on 2020/7/2.
//  Copyright ? 2020 QSDQSB. All rights reserved.
//

import SwiftUI

let TabName: Array<String> = ["飯乎","飯廳","飯跡","飯桶","飯具","垃圾桶"]
let TabLogoName: Array<String> = ["lightbulb","tray.full","clock","person.circle","hammer","trash"]

struct ContentView: View {
    @State private var selection = 0

    var focused = 0
    var body: some View {
        
        TabView(selection: $selection){
            VStack{
                Text("現(xiàn)在選中的Tab:\(selection)")
                    .font(.title)
                Button(action: {
                    withAnimation{
                        self.selection = 1
                    }
                })
                {
                    Text("Change Tab to 1")
                        .font(.largeTitle)

                }
            }
                .tabItem {
                TabContent(TabIndex: 0, Selected: selection == 0)

            }
                .tag(0)
                    
            
            // MARK: - 飯廳
            ZStack{
                Text("現(xiàn)在選中的Tab:\(selection)")
                .font(.title)
            }
                .tabItem {
                    TabContent(TabIndex: 1, Selected: selection == 1)

                }
                .tag(1)
            
            // MARK: - 飯跡
            ZStack{
                Text("現(xiàn)在選中的Tab:\(selection)")
                    .font(.title)
            }
                .tabItem{
                    ZStack{
                    TabContent(TabIndex: 2, Selected: selection == 2)
                    }
                }
                .tag(2)
            
            // MARK: - 飯桶
            ZStack{
                Text("現(xiàn)在選中的Tab:\(selection)")
                    .font(.title)
            }
                .tabItem{
                    TabContent(TabIndex: 3, Selected: selection == 3)
                }
                .tag(3)
            
            Text("飯具")
                .tabItem{
                    TabContent(TabIndex: 4, Selected: selection == 4)
                }
                .tag(4)
        }.accentColor(.pink)
    }
    
    
    
}

func TabContent (TabIndex: Int, Selected: Bool) -> some View {
    return
        VStack {
            Image(systemName: Selected ? (TabLogoName[TabIndex] + ".fill"): TabLogoName[TabIndex])
            Text(TabName[TabIndex])
        }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

當(dāng)然,如果覺(jué)得一遍一遍輸tag很煩的話(huà),用個(gè)ForEach就完事兒了:

                ForEach (1..<3) {Index in
                    ZStack{
                        Text("現(xiàn)在選中的Tab:\(self.selection)")
                            .font(.title)
                    }
                        .tabItem {
                            TabContent(TabIndex: Index, Selected: self.selection == Index)
                            }
                        .tag(Index)
                }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容