第三章:SwiftUI 構(gòu)建CardView吃既,一個列表視圖cell

第一部分

創(chuàng)建顏色主題

為了在應(yīng)用程序中創(chuàng)建一致的外觀考榨,您將創(chuàng)建一個主題,其中包含兩個對比的顏色屬性鹦倚。您將使用主顏色作為視圖的背景顏色河质,使用強調(diào)顏色作為視圖的文本顏色。


SUI020_010-intro@2x.png

注意:

請確保您使用的是本頁面頂部鏈接處提供的起始項目申鱼。下面的步驟使用該項目中定義的顏色愤诱。

步驟1

在項目導航器中,創(chuàng)建一個名為Models的新組捐友。

步驟2

在Models組中,創(chuàng)建一個名為Theme.swift的新的Swift文件溃槐。

步驟3

導入SwiftUI框架而不是Foundation框架匣砖。
盡管在本節(jié)中您并沒有創(chuàng)建一個視圖,但您可以從SwiftUI框架中添加顏色屬性昏滴。SwiftUI將顏色視為可以直接添加到視圖層次結(jié)構(gòu)中的視圖實例猴鲫。

步驟4

創(chuàng)建一個名為Theme的枚舉,其原始值類型為String谣殊。
Swift會自動創(chuàng)建與每個添加到Theme中的case名稱匹配的字符串拂共。
注意事項
編譯器會生成錯誤,因為枚舉必須有case來聲明原始類型姻几。您將在下一步中修復(fù)此錯誤宜狐。
起始項目包括資源目錄势告,并為每個顏色定義了RGBA值。

步驟5

為資產(chǎn)目錄中的Themes文件夾中列出的每種顏色添加case抚恒。
資源目錄中的命名顏色必須與代碼中的引用匹配咱台,因此請確保正確拼寫每個case的名稱。

步驟6

添加一個名為accentColor的Color屬性俭驮,根據(jù)self的值返回.black或.white回溺。
強調(diào)顏色為主題的主色提供了高對比度的補充,確保您的視圖保持可訪問性混萝。

步驟7

添加一個名為mainColor的Color屬性遗遵,使用枚舉的rawValue創(chuàng)建一個顏色。
此屬性從資源目錄中初始化一個顏色逸嘀。

Theme.swift
import SwiftUI


enum Theme: String {
    case bubblegum
    case buttercup
    case indigo
    case lavender
    case magenta
    case navy
    case orange
    case oxblood
    case periwinkle
    case poppy
    case purple
    case seafoam
    case sky
    case tan
    case teal
    case yellow
    
    var accentColor: Color {
        switch self {
        case .bubblegum, .buttercup, .lavender, .orange, .periwinkle, .poppy, .seafoam, .sky, .tan, .teal, .yellow: return .black
        case .indigo, .magenta, .navy, .oxblood, .purple: return .white
        }
    }
    var mainColor: Color {
        Color(rawValue)
    }
}

Section 2

創(chuàng)建每日站會模型

DailyScrum模型將包含以下四個屬性车要,均為簡單值類型:title、attendees厘熟、lengthInMinutes和theme屯蹦。因為DailyScrum主要用于攜帶值數(shù)據(jù),所以您將它聲明為結(jié)構(gòu)體绳姨,使其成為值類型登澜。

Step 1

在Models組中添加一個名為DailyScrum的新Swift文件。

Step 2

創(chuàng)建一個DailyScrum結(jié)構(gòu)體飘庄,包含title脑蠕、attendees、lengthInMinutes和theme屬性跪削。

Step 3

添加一個擴展谴仙,提供一些示例數(shù)據(jù)。

DailyScrum.swift
import Foundation


struct DailyScrum {
    var title: String
    var attendees: [String]
    var lengthInMinutes: Int
    var theme: Theme
}


extension DailyScrum {
    static let sampleData: [DailyScrum] =
    [
        DailyScrum(title: "Design",
                   attendees: ["Cathy", "Daisy", "Simon", "Jonathan"],
                   lengthInMinutes: 10,
                   theme: .yellow),
        DailyScrum(title: "App Dev",
                   attendees: ["Katie", "Gray", "Euna", "Luis", "Darla"],
                   lengthInMinutes: 5,
                   theme: .orange),
        DailyScrum(title: "Web Dev",
                   attendees: ["Chella", "Chris", "Christina", "Eden", "Karla", "Lindsey", "Aga", "Chad", "Jenn", "Sarah"],
                   lengthInMinutes: 5,
                   theme: .poppy)
    ]
}

Section 3

創(chuàng)建卡片視圖

CardView將總結(jié)DailyScrum模型的數(shù)據(jù)碾盐,并顯示標題晃跺、參與人數(shù)和持續(xù)時間。您將從較小的視圖中組合CardView毫玖,每個視圖顯示DailyScrum結(jié)構(gòu)中的一部分數(shù)據(jù)掀虎。
您將更新CardView_Previews結(jié)構(gòu),以便在開發(fā)視圖時獲得即時的可視反饋付枫。


SUI020_030-intro@2x.png

Step 1

添加一個名為CardView的新的SwiftUI視圖文件烹玉。
如果預(yù)覽被暫停了,您可以恢復(fù)它阐滩,以觀察您在代碼中進行的更改在預(yù)覽中的反映二打。

Step 2

添加一個類型為DailyScrum的常量scrum。

注意

編譯器會生成一個錯誤掂榔,因為CardView()初始化程序現(xiàn)在需要一個DailyScrum參數(shù)继效。您將在下一步中解決此問題症杏。

Step 3

在CardView_Previews中,創(chuàng)建一個名為scrum的靜態(tài)變量莲趣,并將其傳遞給CardView的初始化程序鸳慈。

Step 4

使用scrum.theme.mainColor為預(yù)覽指定一個背景顏色。

Step 5

使用previewLayout修飾符將預(yù)覽的寬度設(shè)置為400喧伞,高度設(shè)置為60走芋。
設(shè)置預(yù)覽布局和背景顏色將CardView呈現(xiàn)為它將在List視圖中顯示的樣子。在下一個教程中潘鲫,您將將該視圖嵌入到列表中翁逞。

Step 6

將畫布設(shè)置從Live更改為Selectable。

Step 7

更新Text視圖以顯示scrum的標題溉仑,并將字體樣式設(shè)置為headline挖函。

Step 8

將Text視圖嵌入到具有l(wèi)eading對齊的VStack中。
VStack在垂直線上排列子視圖浊竟,并使用對齊參數(shù)將視圖沿水平軸的位置怨喘。

Step 9

在Spacer后面添加一個HStack,其中嵌套了一個Label用于顯示與會人數(shù)振定。

注意

Label和Image對于SF Symbol使用稍微不同的參數(shù)標簽必怜。在使用堆棧排列視圖中創(chuàng)建的Image使用的是Image(systemName:),而不是Label(:systemImage:)后频。

Step 10

在HStack中添加另一個Label梳庆,并將其系統(tǒng)圖像設(shè)置為“clock”。

Step 11

修改標簽以顯示會議持續(xù)時間卑惜。
您可以使用屬性檢查器自定義視圖膏执,代碼會相應(yīng)更新÷毒茫或者您可以直接在代碼中更改屬性更米。在兩種情況下,預(yù)覽都會更新以反映您的更改毫痕。

Step 12

在標簽之間添加一個Spacer壳快,以顯示圍繞視圖的信息。

CardView.swift
import SwiftUI


struct CardView: View {
    let scrum: DailyScrum
    var body: some View {
        VStack(alignment: .leading) {
            Text(scrum.title)
                .font(.headline)
            Spacer()
            HStack {
                Label("\(scrum.attendees.count)", systemImage: "person.3")
                Label("\(scrum.lengthInMinutes)", systemImage: "clock")
            }
        }
    }
}


struct CardView_Previews: PreviewProvider {
    static var scrum = DailyScrum.sampleData[0]
    static var previews: some View {
        CardView(scrum: scrum)
            .background(scrum.theme.mainColor)
            .previewLayout(.fixed(width: 400, height: 60))
    }
}

第四節(jié):美化卡片

卡片視圖顯示有關(guān)每日Scrum的信息镇草。在這一部分中,您將為卡片視圖添加樣式瘤旨,突出顯示最重要的信息梯啤,并修改視覺組件,以確保在明亮和暗黑模式下文本和背景視圖之間有足夠的對比度存哲。

Step 1

給會議時長標簽添加20個點的尾部填充因宇。
提示
您還可以在視圖的.leading七婴、.top和.bottom邊緣添加填充。

Step 2

將HStack中的所有字體樣式設(shè)置為標題察滑。
在標簽和圖像中使用的SF Symbols會隨著字體權(quán)重和大小的變化進行合理的縮放和對齊打厘。

Step 3

給VStack添加填充,使所有內(nèi)容從邊緣處靠近贺辰。

Step 4

將Xcode預(yù)覽模式從"Selectable"更改為"Color Scheme Variants"户盯,以在明亮和暗黑外觀中呈現(xiàn)視圖。
在暗黑模式中饲化,默認的淺色文本與黃色背景之間的對比度不足莽鸭。

Step 5

使用scrum.theme.accentColor設(shè)置foregroundColor。
在Theme.swift中定義的accentColor變量會根據(jù)明亮或暗黑主題返回黑色或白色吃靠。

CardView.swift
import SwiftUI


struct CardView: View {
    let scrum: DailyScrum
    var body: some View {
        VStack(alignment: .leading) {
            Text(scrum.title)
                .font(.headline)
            Spacer()
            HStack {
                Label("\(scrum.attendees.count)", systemImage: "person.3")
                Spacer()
                Label("\(scrum.lengthInMinutes)", systemImage: "clock")
                    .padding(.trailing, 20)
            }
            .font(.caption)
        }
        .padding()
        .foregroundColor(scrum.theme.accentColor)
    }
}


struct CardView_Previews: PreviewProvider {
    static var scrum = DailyScrum.sampleData[0]
    static var previews: some View {
        CardView(scrum: scrum)
            .background(scrum.theme.mainColor)
            .previewLayout(.fixed(width: 400, height: 60))
    }
}

Section 5

自定義標簽樣式

接下來硫眨,您將創(chuàng)建一個標簽樣式,將會議時長和時鐘圖標水平堆疊在一起巢块。通過使用LabelStyle協(xié)議礁阁,您可以通過在多個視圖中重用相同的標簽樣式來創(chuàng)建一致的設(shè)計。

Step 1

創(chuàng)建一個名為TrailingIconLabelStyle.swift的新的Swift文件族奢。

Step 2

導入SwiftUI姥闭。

Step 3

創(chuàng)建一個名為TrailingIconLabelStyle的新結(jié)構(gòu)體,并符合LabelStyle協(xié)議歹鱼。
提示
如果您不想創(chuàng)建自定義的標簽樣式泣栈,您可以使用內(nèi)置的標簽樣式之一,它們使用系統(tǒng)標準布局顯示圖標弥姻、標題或兩者南片。

注意

編譯器會生成錯誤,因為該結(jié)構(gòu)體不符合LabelStyle協(xié)議的要求庭敦。

Step 4

創(chuàng)建一個空的makeBody(configuration:)函數(shù)疼进。
系統(tǒng)會在使用此樣式作為當前標簽樣式的視圖層次結(jié)構(gòu)中的每個Label實例中調(diào)用此方法。

注意

現(xiàn)在您的項目可以編譯通過秧廉,沒有錯誤了伞广。

Step 5

添加一個HStack。

Step 6

在HStack內(nèi)部添加configuration.title和configuration.icon疼电。
configuration參數(shù)是一個LabelStyleConfiguration嚼锄,其中包含圖標和標題視圖。這些視圖表示標簽的圖像和標簽文本蔽豺。

Step 7

在LabelStyle上添加一個擴展区丑,創(chuàng)建一個名為trailingIcon的靜態(tài)屬性。
因為您將標簽樣式定義為靜態(tài)屬性,所以可以使用前導點語法來調(diào)用它沧侥,這樣可以使您的代碼更易讀可霎。

Step 8

在CardView.swift文件中的lengthInMinutes標簽上,用新的標簽樣式替換padding宴杀。
現(xiàn)在癣朗,時鐘圖標對齊到尾部,與參與人數(shù)標簽對齊。
在視覺上,CardView已經(jīng)完成游岳,您可以在列表中顯示它毡们。在這之前,您將使用無障礙修飾符來改善VoiceOver用戶的體驗。

TrailingIconLabelStyle.swift
import SwiftUI


struct TrailingIconLabelStyle: LabelStyle {
    func makeBody(configuration: Configuration) -> some View {
        HStack {
            configuration.title
            configuration.icon
        }
    }
}
CardView.swift
import SwiftUI


struct CardView: View {
    let scrum: DailyScrum
    
    var body: some View {
        VStack(alignment: .leading) {
            Text(scrum.title)
                .font(.headline)
            Spacer()
            HStack {
                Label("\(scrum.attendees.count)", systemImage: "person.3")
                Spacer()
                Label("\(scrum.lengthInMinutes)", systemImage: "clock")
                    .labelStyle(.trailingIcon)
            }
            .font(.caption)
        }
        .padding()
        .foregroundColor(scrum.theme.accentColor)
    }
}


struct CardView_Previews: PreviewProvider {
    static var scrum = DailyScrum.sampleData[0]
    static var previews: some View {
        CardView(scrum: scrum)
            .background(scrum.theme.mainColor)
            .previewLayout(.fixed(width: 400, height: 60))
    }
}

Section 6

使卡片視圖具有可訪問性

現(xiàn)在CardView在視覺上已經(jīng)布局完成,您將使其對所有用戶具有可訪問性。您將為您的視圖添加無障礙修飾符穗酥,以使VoiceOver更容易理解和導航您的界面。
CardView包含一個帶有時鐘圖像和表示會議時長的數(shù)字的標簽惠遏。它還包含一個人物圖像和與會人數(shù)砾跃。
您將添加使用字符串插值的無障礙標簽,以使標簽成為視圖的有意義描述节吮。VoiceOver將讀取“4名與會人員”和“10分鐘會議”抽高。

Step 1

在顯示scrum標題的文本視圖上應(yīng)用accessibilityAddTraits(.isHeader)修飾符。
此修飾符通過讀取scrum標題后跟“標題”來幫助傳達視圖的信息架構(gòu)透绩。

Step 2

使用accessibility修飾符為HStack中的第一個Label添加描述其內(nèi)容的標簽翘骂。

Step 3

為HStack中的第二個Label添加類似的accessibility修飾符。

CardView.swift
import SwiftUI


struct CardView: View {
    let scrum: DailyScrum


    var body: some View {
        VStack(alignment: .leading) {
            Text(scrum.title)
                .font(.headline)
                .accessibilityAddTraits(.isHeader)
            Spacer()
            HStack {
                Label("\(scrum.attendees.count)", systemImage: "person.3")
                    .accessibilityLabel("\(scrum.attendees.count) attendees")
                Spacer()
                Label("\(scrum.lengthInMinutes)", systemImage: "clock")
                    .accessibilityLabel("\(scrum.lengthInMinutes) minute meeting")
                    .labelStyle(.trailingIcon)
            }
            .font(.caption)
        }
        .padding()
        .foregroundColor(scrum.theme.accentColor)
    }
}


struct CardView_Previews: PreviewProvider {
    static var scrum = DailyScrum.sampleData[0]
    static var previews: some View {
        CardView(scrum: scrum)
            .background(scrum.theme.mainColor)
            .previewLayout(.fixed(width: 400, height: 60))
    }
}

下一個教程將向您展示如何在SwiftUI List中使用CardView帚豪。您將了解到SwiftUI如何通過將較小的視圖組合在一起來輕松構(gòu)建一個大而復(fù)雜的視圖碳竟,就像您剛剛創(chuàng)建的視圖一樣。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末狸臣,一起剝皮案震驚了整個濱河市莹桅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌烛亦,老刑警劉巖诈泼,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異煤禽,居然都是意外死亡铐达,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門檬果,熙熙樓的掌柜王于貴愁眉苦臉地迎上來娶桦,“玉大人,你說我怎么就攤上這事≈云瑁” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵知牌,是天一觀的道長祈争。 經(jīng)常有香客問我,道長角寸,這世上最難降的妖魔是什么菩混? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮扁藕,結(jié)果婚禮上沮峡,老公的妹妹穿的比我還像新娘。我一直安慰自己亿柑,他們只是感情好邢疙,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著望薄,像睡著了一般疟游。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上痕支,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天颁虐,我揣著相機與錄音,去河邊找鬼卧须。 笑死另绩,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的花嘶。 我是一名探鬼主播笋籽,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼察绷!你這毒婦竟也來了干签?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤拆撼,失蹤者是張志新(化名)和其女友劉穎容劳,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體闸度,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡竭贩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了莺禁。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片留量。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出楼熄,到底是詐尸還是另有隱情忆绰,我是刑警寧澤,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布可岂,位于F島的核電站错敢,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏缕粹。R本人自食惡果不足惜稚茅,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望平斩。 院中可真熱鬧亚享,春花似錦、人聲如沸绘面。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽飒货。三九已至魄衅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間塘辅,已是汗流浹背晃虫。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留扣墩,地道東北人哲银。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像呻惕,于是被迫代替她去往敵國和親荆责。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

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