第二章:SwiftUI基礎(chǔ)知識(shí), 使用堆棧布局視圖

使用SwiftUI的聲明性語(yǔ)法虎韵,創(chuàng)建易稠、修改和組合視圖,以便使用Scrumdinger的應(yīng)用程序來(lái)管理會(huì)議包蓝。通過(guò)將一組視圖排列在一起缩多,創(chuàng)建會(huì)議計(jì)時(shí)器屏幕。隨著您在模塊中的進(jìn)展养晋,您將會(huì)反復(fù)回顧計(jì)時(shí)器屏幕衬吆,以便朝著最終設(shè)計(jì)的目標(biāo)進(jìn)行工作。
按照以下步驟開(kāi)始您的新項(xiàng)目绳泉,或者打開(kāi)已完成的項(xiàng)目逊抡,自行探索其中的代碼。

第1節(jié)

創(chuàng)建項(xiàng)目

在整個(gè)模塊中,通過(guò)創(chuàng)建Scrumdinger應(yīng)用程序冒嫡,您將學(xué)習(xí)應(yīng)用程序開(kāi)發(fā)的基礎(chǔ)知識(shí)拇勃。在向應(yīng)用程序添加新功能的過(guò)程中,您將探索Xcode和SwiftUI的基礎(chǔ)知識(shí)孝凌。在本節(jié)中方咆,您將創(chuàng)建Scrumdinger的Xcode項(xiàng)目。


SUI010-010-intro@2x.png

步驟1

使用iOS App模板創(chuàng)建一個(gè)新項(xiàng)目蟀架。


SUI010-010-010@2x.png

步驟2

在項(xiàng)目選項(xiàng)中瓣赂,將產(chǎn)品命名為“Scrumdinger”,點(diǎn)擊界面彈出菜單片拍,并選擇SwiftUI煌集。
模板包含了一個(gè)根視圖的起始文件ContentView.swift,以及定義應(yīng)用程序入口點(diǎn)的文件ScrumdingerApp.swift捌省。
提示:
如果您對(duì)Xcode還不熟悉苫纤,請(qǐng)了解主窗口的相關(guān)信息,并了解如何創(chuàng)建一個(gè)項(xiàng)目纲缓。


SUI010-010-020@2x.png

步驟3

選擇一個(gè)保存項(xiàng)目的位置卷拘。


SUI010-010-030@2x.png

第2節(jié)

組合視圖

視圖定義了您的用戶(hù)界面的一部分。它們是應(yīng)用程序的構(gòu)建塊祝高。通過(guò)將小而簡(jiǎn)單的視圖組合在一起栗弟,您可以構(gòu)建一個(gè)復(fù)雜的視圖。在本節(jié)中褂策,您將構(gòu)建計(jì)時(shí)器屏幕的標(biāo)題横腿,以顯示會(huì)議的已用時(shí)間和剩余時(shí)間颓屑。


SUI010-020-intro@2x.png

步驟1

打開(kāi)ContentView.swift斤寂。
默認(rèn)的SwiftUI視圖文件聲明了兩個(gè)結(jié)構(gòu)體。第一個(gè)結(jié)構(gòu)體遵循View協(xié)議揪惦,該協(xié)議有一個(gè)要求:一個(gè)返回View的body屬性遍搞。在body屬性中,您描述視圖的內(nèi)容器腋、布局和行為溪猿。第二個(gè)結(jié)構(gòu)體為該視圖定義了一個(gè)預(yù)覽,以在畫(huà)布上顯示纫塌。

import SwiftUI
    
struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundColor(.accentColor)
            Text("Hello, world!")
        }
        .padding()
    }
}
    
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

您將對(duì)ContentView.swift進(jìn)行重構(gòu)诊县,以為其指定一個(gè)與您的應(yīng)用程序目的相關(guān)的名稱(chēng)。

步驟2

對(duì)ContentView結(jié)構(gòu)體進(jìn)行控制點(diǎn)擊措左,選擇Refactor > Rename依痊,并將結(jié)構(gòu)體重命名為MeetingView。
您還可以將預(yù)覽結(jié)構(gòu)體重命名為MeetingView_Previews怎披,以保持命名的一致性胸嘁。


WX20230626-112636@2x.png

步驟3

將現(xiàn)有body的內(nèi)容替換為ProgressView瓶摆,并使用占位數(shù)據(jù)初始化視圖。
當(dāng)您在項(xiàng)目導(dǎo)航器中選擇一個(gè)SwiftUI文件時(shí)性宏,畫(huà)布會(huì)在編輯器旁邊打開(kāi)群井。畫(huà)布會(huì)顯示運(yùn)行時(shí)視圖的預(yù)覽。

MeetingView.swift
import SwiftUI


struct MeetingView: View {
    var body: some View {
        ProgressView(value: 10, total: 15)
    }
}


struct MeetingView_Previews: PreviewProvider {
    static var previews: some View {
        MeetingView()
    }
}

步驟4

將進(jìn)度視圖的值從10更改為5毫胜,并觀察畫(huà)布中的進(jìn)度視圖更新书斜。
您將使用進(jìn)度視圖來(lái)顯示Scrum期間已經(jīng)過(guò)的時(shí)間的百分比。進(jìn)度視圖還可以顯示不確定的進(jìn)度指蚁,比如當(dāng)應(yīng)用程序正在加載數(shù)據(jù)時(shí)菩佑。

MeetingView.swift
import SwiftUI


struct MeetingView: View {
    var body: some View {
        ProgressView(value: 5, total: 15)
    }
}


struct MeetingView_Previews: PreviewProvider {
    static var previews: some View {
        MeetingView()
    }
}

步驟5

按住Command鍵點(diǎn)擊ProgressView,然后選擇“Embed in VStack”凝化。
堆棧將視圖水平稍坯、垂直或前后分組。您可以使用堆棧來(lái)組合和層疊視圖組件搓劫。

步驟6

在代碼編輯器中創(chuàng)建一個(gè)HStack瞧哟,點(diǎn)擊庫(kù)按鈕,并將一個(gè)文本視圖拖到HStack中枪向,并設(shè)置值為"Seconds Elapsed"勤揩。
無(wú)論您使用源代碼編輯器、畫(huà)布秘蛔、庫(kù)或檢查器來(lái)修改視圖陨亡,您的代碼都會(huì)保持更新。


WX20230626-113227@2x.png

步驟7

添加另一個(gè)值為"Seconds Remaining"的文本視圖深员。

MeetingView.swift
import SwiftUI


struct MeetingView: View {
    var body: some View {
        VStack {
            ProgressView(value: 5, total: 15)
            HStack {
                Text("Seconds Elapsed")
                Text("Seconds Remaining")
            }
        }
    }
}


struct MeetingView_Previews: PreviewProvider {
    static var previews: some View {
        MeetingView()
    }
}

步驟8

將每個(gè)文本視圖嵌套在一個(gè)VStack中负蠕。

步驟9

在第一個(gè)文本視圖下方添加一個(gè)標(biāo)題為"300"、系統(tǒng)圖片為"hourglass.tophalf.fill"的標(biāo)簽倦畅。
該圖像使用了SF Symbols 4中的一個(gè)遮糖。系統(tǒng)將這些符號(hào)視為字體,因此它們會(huì)根據(jù)用戶(hù)設(shè)備的設(shè)置進(jìn)行動(dòng)態(tài)縮放叠赐。

MeetingView.swift
import SwiftUI


struct MeetingView: View {
    var body: some View {
        VStack {
            ProgressView(value: 5, total: 15)
            HStack {
                VStack {
                    Text("Seconds Elapsed")
                    Label("300", systemImage: "hourglass.tophalf.fill")
                }
                VStack {
                    Text("Seconds Remaining")
                }
            }
        }
    }
}


struct MeetingView_Previews: PreviewProvider {
    static var previews: some View {
        MeetingView()
    }
}

步驟10

在第二個(gè)文本視圖下方添加一個(gè)標(biāo)題為"600"欲账、系統(tǒng)圖片為"hourglass.bottomhalf.fill"的標(biāo)簽。

MeetingView.swift
import SwiftUI


struct MeetingView: View {
    var body: some View {
        VStack {
            ProgressView(value: 5, total: 15)
            HStack {
                VStack {
                    Text("Seconds Elapsed")
                    Label("300", systemImage: "hourglass.tophalf.fill")
                }
                VStack {
                    Text("Seconds Remaining")
                    Label("600", systemImage: "hourglass.bottomhalf.fill")
                }
            }
        }
    }
}


struct MeetingView_Previews: PreviewProvider {
    static var previews: some View {
        MeetingView()
    }
}

第3節(jié)

修改和樣式化視圖

現(xiàn)在您已經(jīng)在標(biāo)題中創(chuàng)建了基本視圖芭概,您將對(duì)會(huì)議計(jì)時(shí)器屏幕的其余部分進(jìn)行原型設(shè)計(jì)和樣式設(shè)置赛不。您將添加內(nèi)置修飾符來(lái)調(diào)整標(biāo)題的外觀。您還將創(chuàng)建額外的堆棧和視圖罢洲,并開(kāi)始添加控件踢故。

您將通過(guò)調(diào)整視圖的間距來(lái)開(kāi)始樣式化標(biāo)題。

步驟1

在每個(gè)VStack之間添加一個(gè)spacer,以利用包含父視圖中的可用空間畴椰。

步驟2

在包圍“Seconds Elapsed”的VStack中添加前導(dǎo)對(duì)齊臊诊,并在包圍“Seconds Remaining”的VStack中添加尾部對(duì)齊。
這些對(duì)齊方式覆蓋了默認(rèn)的居中對(duì)齊方式斜脂。某些系統(tǒng)使用左對(duì)齊和右對(duì)齊抓艳。SwiftUI使用前導(dǎo)對(duì)齊和尾部對(duì)齊來(lái)簡(jiǎn)化您的應(yīng)用程序的本地化。
提示
您還可以通過(guò)選擇VStack并在屬性檢查器中使用對(duì)齊選項(xiàng)來(lái)設(shè)置對(duì)齊方式帚戳。

MeetingView.swift
import SwiftUI


struct MeetingView: View {
    var body: some View {
        VStack {
            ProgressView(value: 5, total: 15)
            HStack {
                VStack(alignment: .leading) {
                    Text("Seconds Elapsed")
                    Label("300", systemImage: "hourglass.tophalf.fill")
                }
                Spacer()
                VStack(alignment: .trailing) {
                    Text("Seconds Remaining")
                    Label("600", systemImage: "hourglass.bottomhalf.fill")
                }
            }
        }
    }
}


struct MeetingView_Previews: PreviewProvider {
    static var previews: some View {
        MeetingView()
    }
}

步驟3

對(duì)文本視圖添加.font(.caption)修飾符以減小文本的大小玷或。
要自定義SwiftUI視圖,您可以調(diào)用稱(chēng)為修飾符的方法片任。每個(gè)修飾符都返回一個(gè)新的視圖偏友。您可以在單個(gè)視圖上使用多個(gè)修飾符。要鏈?zhǔn)秸{(diào)用修飾符对供,請(qǐng)將它們垂直堆疊位他。

現(xiàn)在標(biāo)題具有適當(dāng)?shù)拈g距,您將為屏幕中央顯示的圓形計(jì)時(shí)器視圖創(chuàng)建一個(gè)占位符产场。

步驟4

添加一個(gè)具有邊框的圓形形狀作為占位符鹅髓。
您將在以后的教程中完善圓形計(jì)時(shí)器視圖的設(shè)計(jì)。

import SwiftUI


struct MeetingView: View {
    var body: some View {
        VStack {
            ProgressView(value: 5, total: 15)
            HStack {
                VStack(alignment: .leading) {
                    Text("Seconds Elapsed")
                        .font(.caption)
                    Label("300", systemImage: "hourglass.tophalf.fill")
                }
                Spacer()
                VStack(alignment: .trailing) {
                    Text("Seconds Remaining")
                        .font(.caption)
                    Label("600", systemImage: "hourglass.bottomhalf.fill")
                }
            }
            Circle()
                .strokeBorder(lineWidth: 24)
            HStack {
                Text("Speaker 1 of 3")
            }
        }
    }
}

通過(guò)創(chuàng)建頁(yè)腳來(lái)完成會(huì)議計(jì)時(shí)器屏幕的原型設(shè)計(jì)京景。

步驟5

添加一個(gè)包含文本視圖的HStack窿冯,顯示"Speaker 1 of 3"。

步驟6

添加一個(gè)使用forward.fill圖像作為標(biāo)簽的按鈕确徙。
暫時(shí)保留按鈕的操作為空醒串。在以后的教程中,您將使操作將計(jì)時(shí)器環(huán)推進(jìn)到下一個(gè)發(fā)言人鄙皇。

步驟7

在文本和按鈕之間添加一個(gè)spacer芜赌。

步驟8

對(duì)頂層的VStack添加padding,將視圖從邊緣向內(nèi)移動(dòng)育苟。
當(dāng)您省略padding(_:)的參數(shù)時(shí)较鼓,SwiftUI會(huì)選擇適合平臺(tái)和展示上下文的默認(rèn)值椎木。

MeetingView.swift
import SwiftUI


struct MeetingView: View {
    var body: some View {
        VStack {
            ProgressView(value: 5, total: 15)
            HStack {
                VStack(alignment: .leading) {
                    Text("Seconds Elapsed")
                        .font(.caption)
                    Label("300", systemImage: "hourglass.tophalf.fill")
                }
                Spacer()
                VStack(alignment: .trailing) {
                    Text("Seconds Remaining")
                        .font(.caption)
                    Label("600", systemImage: "hourglass.bottomhalf.fill")
                }
            }
            Circle()
                .strokeBorder(lineWidth: 24)
            HStack {
                Text("Speaker 1 of 3")
                Spacer()
                Button(action: {}) {
                    Image(systemName: "forward.fill")
                }
            }
        }
        .padding()
    }
}
SUI010-030-080-preview.png

第4節(jié)

補(bǔ)充輔助功能數(shù)據(jù)

SwiftUI具有內(nèi)置的輔助功能违柏,因此您可以在很少的額外工作下獲得輔助功能支持。例如香椎,文本視圖中的字符串內(nèi)容會(huì)自動(dòng)對(duì)設(shè)備功能(如VoiceOver)進(jìn)行輔助訪問(wèn)漱竖。但有時(shí),您可能希望補(bǔ)充推斷的數(shù)據(jù)畜伐,以增強(qiáng)用戶(hù)的輔助功能體驗(yàn)馍惹。

步驟1

忽略標(biāo)題欄中HStack的子視圖的推斷輔助功能標(biāo)簽和值。
在接下來(lái)的幾個(gè)步驟中添加補(bǔ)充數(shù)據(jù)可以改進(jìn)輔助功能體驗(yàn)。

步驟2

為HStack添加輔助功能標(biāo)簽万矾,傳遞一個(gè)有意義的標(biāo)簽名稱(chēng)悼吱。
考慮標(biāo)簽和值中是否有足夠的上下文讓用戶(hù)理解元素的目的。在這種情況下良狈,您可以通過(guò)添加一個(gè)標(biāo)簽來(lái)補(bǔ)充數(shù)據(jù)后添,讓VoiceOver用戶(hù)只需聽(tīng)取一個(gè)輸出的標(biāo)簽,顯示最重要的信息薪丁。

步驟3

為剩余時(shí)間添加輔助功能值到HStack遇西。
因?yàn)槟幸夂雎粤俗右晥D的值,所以您需要為HStack添加一個(gè)值严嗜。否則粱檀,SwiftUI會(huì)自動(dòng)推斷子視圖的值。

步驟4

為前進(jìn)按鈕添加輔助功能標(biāo)簽漫玄。
默認(rèn)情況下茄蚯,VoiceOver會(huì)讀取圖像的系統(tǒng)名稱(chēng):forward.fill。當(dāng)您添加輔助功能標(biāo)簽時(shí)睦优,VoiceOver會(huì)先讀取標(biāo)簽文本第队,然后是內(nèi)在的輔助功能特征:“下一個(gè)發(fā)言者。按鈕刨秆〉是”
使用這四個(gè)修飾符,您可以增強(qiáng)用戶(hù)的輔助功能體驗(yàn)衡未。

MeetingView.swift
import SwiftUI


struct MeetingView: View {
    var body: some View {
        VStack {
            ProgressView(value: 5, total: 15)
            HStack {
                VStack(alignment: .leading) {
                    Text("Seconds Elapsed")
                        .font(.caption)
                    Label("300", systemImage: "hourglass.tophalf.fill")
                }
                Spacer()
                VStack(alignment: .trailing) {
                    Text("Seconds Remaining")
                        .font(.caption)
                    Label("600", systemImage: "hourglass.bottomhalf.fill")
                }
            }
            .accessibilityElement(children: .ignore)
            .accessibilityLabel("Time remaining")
            .accessibilityValue("10 minutes")
            Circle()
                .strokeBorder(lineWidth: 24)
            HStack {
                Text("Speaker 1 of 3")
                Spacer()
                Button(action: {}) {
                    Image(systemName: "forward.fill")
                }
                .accessibilityLabel("Next speaker")
            }
        }
        .padding()
    }
}


struct MeetingView_Previews: PreviewProvider {
    static var previews: some View {
        MeetingView()
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末尸执,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子缓醋,更是在濱河造成了極大的恐慌如失,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件送粱,死亡現(xiàn)場(chǎng)離奇詭異褪贵,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)抗俄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)脆丁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人动雹,你說(shuō)我怎么就攤上這事槽卫。” “怎么了胰蝠?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵歼培,是天一觀的道長(zhǎng)震蒋。 經(jīng)常有香客問(wèn)我,道長(zhǎng)躲庄,這世上最難降的妖魔是什么查剖? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮噪窘,結(jié)果婚禮上梗搅,老公的妹妹穿的比我還像新娘。我一直安慰自己效览,他們只是感情好无切,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著丐枉,像睡著了一般哆键。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上瘦锹,一...
    開(kāi)封第一講書(shū)人閱讀 51,146評(píng)論 1 297
  • 那天籍嘹,我揣著相機(jī)與錄音,去河邊找鬼弯院。 笑死辱士,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的听绳。 我是一名探鬼主播颂碘,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼椅挣!你這毒婦竟也來(lái)了头岔?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤鼠证,失蹤者是張志新(化名)和其女友劉穎峡竣,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體量九,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡适掰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了荠列。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片类浪。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖弯予,靈堂內(nèi)的尸體忽然破棺而出戚宦,到底是詐尸還是另有隱情个曙,我是刑警寧澤锈嫩,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布受楼,位于F島的核電站,受9級(jí)特大地震影響呼寸,放射性物質(zhì)發(fā)生泄漏艳汽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一对雪、第九天 我趴在偏房一處隱蔽的房頂上張望河狐。 院中可真熱鬧,春花似錦瑟捣、人聲如沸馋艺。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)捐祠。三九已至,卻和暖如春桑李,著一層夾襖步出監(jiān)牢的瞬間踱蛀,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工贵白, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留率拒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓禁荒,卻偏偏與公主長(zhǎng)得像猬膨,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子呛伴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

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