歡迎閱讀 SwiftUI 小技巧系列教程!在這篇文章中,我們將實作一個常見的手機 UI 設計 —— Card UI。SwiftUI 框架讓我們輕易構建 App UI,我們會在文章中展示這一點。你將會看到我們可以使用堆疊 (stack)、圖像、和文本視圖,來像這樣創建卡片視圖 (card view)。
![swiftui-card-ui-view](https://www.appcoda.com.tw/content/images/2019/11/swiftui-scrollview-1-1024x497.png)
請注意,本篇教程需要你在 macOS Catalina (v10.15)上運行 Xcode 11。
建立一個卡片式的 UI
如果你還沒有開啟 Xcode,請打開它,並使用 Single View Application 模板來建立一個新專案。在下一個畫面,設定專案名稱為 SwiftUIScrollView
(或你喜歡的名稱),並填入所需要的值。請確認你有在 User Interface 選項中選取 SwiftUI
。
如果你還不熟悉 SwiftUI,你可能會在 ContentView.swift
文件中為 UI 編寫程式碼。這當然沒有問題,但是我想向你展示一個更好的方法來組織程式碼。為了實作卡片視圖,讓我們為它建立一個單獨的文件。在專案導航器中,右鍵單擊SwiftUIScrollView
,並選擇 New File…。
![](https://www.appcoda.com.tw/content/images/2019/11/swiftui-scrollview-3-1024x485.png)
在 User Interface 區塊,選取 SwiftUI View 模板並點擊 Next 來建立檔案。將檔案命名為 CardView
,並儲存在專案資料夾內。
![swiftui-card-ui-view-4](https://www.appcoda.com.tw/content/images/2019/11/swiftui-scrollview-4-1024x735.png)
CardView.swift
中的程式碼與 ContentView.swift
的程式碼很接近。同樣地,你可以在畫布中檢視 UI。
![](https://www.appcoda.com.tw/content/images/2019/11/swiftui-scrollview-5-1024x421.png)
準備圖片檔
現在我們準備要寫卡片視圖的程式碼。首先,你需要準備圖檔並將其匯入素材目錄。如果你不想要準備自己的圖片,你可以在這裡下載圖片檔,將圖片檔解壓縮後,選取 Assets.xcassets
,並將其拖曳至素材目錄。
![](https://www.appcoda.com.tw/content/images/2019/11/swiftui-scrollview-6-1024x344.png)
實作卡片視圖
現在切回 CardView.swift
檔。如果你再看一下以下圖片,這個卡片視圖是由兩個部分組成的:上面的部分是圖片,而下面的部分是文字敘述。
![swiftui-card-ui-view](https://www.appcoda.com.tw/content/images/2019/11/swiftui-scrollview-1-1-1024x497.png)
讓我們從圖片開始。我將會設計讓圖片可以調整大小,讓它因應畫面縮放,同時保持長寬比例。你可以撰寫程式碼如下:
struct CardView: View {
var body: some View {
Image("swiftui-button")
.resizable()
.aspectRatio(contentMode: .fit)
}
}
如果你忘記了這兩個修飾器是甚麼,可以回去有關 Image
物件的章節閱讀一下。接下來實作文字敘述部分,你可以將程式碼撰寫如下:
VStack(alignment: .leading) {
Text("SwiftUI")
.font(.headline)
.foregroundColor(.secondary)
Text("Drawing a Border with Rounded Corners")
.font(.title)
.fontWeight(.black)
.foregroundColor(.primary)
.lineLimit(3)
Text("Written by Simon Ng".uppercased())
.font(.caption)
.foregroundColor(.secondary)
}
很明顯的,你需要使用 Text
來建立文字視圖。因為我們在敘述中有三種文字視圖,以垂直方式並排,所以我們使用一個 VStack
來嵌入它們。對於 VStack
,我們指定以 .leading
來對齊,這會將文字視圖對齊堆疊視圖的左側。
我們已經在之前的教學文章討論過這些 Text
的修飾器,如果你對任何一個修飾器有所疑問的話,可以回去參考看看。不過這裡要提出來說明的,是 .primary
與 .secondary
顏色。當你在 foregroundColor
修飾器指定標準顏色,像是 .black
與 .purple
,iOS 13 導入一套系統顏色,包括了三原色 (primary colors)、三間色 (secondary colors) 以及再間色 (tertiary colors) 的變化,透過這個顏色變化,你的 App 可以很容易地支援淡色與深色模式,舉例來說,文字視圖的主色預設以淡色模式設為黑色。當 App 切換到深色模式,主色將會被調整成白色。這都會由 iOS 自動來調整,所以你不用再另外寫支援深色模式的程式碼。我們將在後面的章節深入討論深色模式。
要將圖片與這些文字視圖垂直排列,我們使用 VStack
來嵌入它們,目前的佈局如下圖所示。
![](https://www.appcoda.com.tw/content/images/2019/11/swiftui-scrollview-7-1024x575.png)
但我們還沒完成,還有幾件事需要實作。首先,如果敘述區塊要對齊圖片的邊緣,該如何做呢?
依照我們所學,我們可以在一個 HStack
嵌入文字視圖的 VStack
。然後,我們將使用一個彈性空間 (Spacer
) 來將 VStack
往左推。讓我們來看看是否可行。
如果你已經變更程式碼如下,這個文字視圖的 VStack
會對齊其畫面的左側。不過,前端被截掉了。
![](https://www.appcoda.com.tw/content/images/2019/11/swiftui-scrollview-8-1024x575.png)
調整佈局順序
文字堆疊與彈性空間 (spacer) 預設佔據了父視圖的一半,這也是標題無法完整呈現的原因。要解決這個問題,你需要使用 layoutPriority
修飾器來調整文字堆疊的佈局優先度 (layout priority)。數值越大表示優先度越高。這表示如果我們設定文字視圖的 VStack
佈局優先度為較大的值時,iOS 就會在配置空間給彈性空間前,提供更多空間來完全渲染文字視圖。下圖為最後的結果。
![](https://www.appcoda.com.tw/content/images/2019/11/swiftui-scrollview-9-1024x575.png)
如果在 HStack
加上一些間距 (padding) 應該會更好。插入 padding
修飾器如下:
HStack {
VStack(alignment: .leading) {
.
.
.
}
.layoutPriority(100)
Spacer()
}
.padding()
最後是外框部分。在上一篇文章,我們有討論過如何畫出具有圓角的外框。我們可以使用 overlay
修飾器,並使用 RoundedRectangle
來畫出外框。以下是完整的程式碼:
struct CardView: View {
var body: some View {
VStack {
Image("swiftui-button")
.resizable()
.aspectRatio(contentMode: .fit)
HStack {
VStack(alignment: .leading) {
Text("SwiftUI")
.font(.headline)
.foregroundColor(.secondary)
Text("Drawing a Border with Rounded Corners")
.font(.title)
.fontWeight(.black)
.foregroundColor(.primary)
.lineLimit(3)
Text("Written by Simon Ng".uppercased())
.font(.caption)
.foregroundColor(.secondary)
}
.layoutPriority(100)
Spacer()
}
.padding()
}
.cornerRadius(10)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color(.sRGB, red: 150/255, green: 150/255, blue: 150/255, opacity: 0.1), lineWidth: 1)
)
.padding([.top, .horizontal])
}
}
除了外框之外,我也在頂部、和左右兩側分別加入了一些間距。現在,我們已經建立好卡片視圖的佈局了。
![](https://www.appcoda.com.tw/content/images/2019/11/swiftui-scrollview-10-1-1024x576.png)
讓卡片視圖更彈性
雖然目前卡片視圖目前看起來沒問題,但我們是把圖片與文字用程式碼固定寫入。為了讓它更彈性,我們重構一下程式碼。首先,在 CardView
宣告 image、category、heading 與 author 這些變數:
var image: String
var category: String
var heading: String
var author: String
接下來,將 Image
與 Text
視圖以這些變數替代:
VStack {
Image(image)
.resizable()
.aspectRatio(contentMode: .fit)
HStack {
VStack(alignment: .leading) {
Text(category)
.font(.headline)
.foregroundColor(.secondary)
Text(heading)
.font(.title)
.fontWeight(.black)
.foregroundColor(.primary)
.lineLimit(3)
Text(author.uppercased())
.font(.caption)
.foregroundColor(.secondary)
}
.layoutPriority(100)
Spacer()
}
.padding()
}
做完變更之後,你將會在 CardView_Previews
結構中見到一個錯誤。這是因為我們在 CardView
導入了一些變數,所以在使用它時,我們要指定參數。
![](https://www.appcoda.com.tw/content/images/2019/11/swiftui-scrollview-11-1024x170.png)
將程式碼以下面這段替代:
struct CardView_Previews: PreviewProvider {
static var previews: some View {
CardView(image: "swiftui-button", category: "SwiftUI", heading: "Drawing a Border with Rounded Corners", author: "Simon Ng")
}
}
錯誤將會被修正,現在你已經建立了一個能夠接受不同圖片與文字的彈性 CardView
。你可以基於構建好的內容,進一步應用此卡片視圖來構建一個流暢的列表 UI。
![swiftui-card-view-list](https://www.appcoda.com.tw/content/images/2019/11/swiftui-scrollview-2-1024x679.png)
你覺得這個 SwiftUI 小技巧教學系列怎樣呢?如果你喜歡本篇文章,覺得它對你有幫助,請留言讓我知道。另外,如果你對我們的下一個技巧有任何建議,也請留言告訴我們。