昨天我們討論 MVVM 架構,並介紹如何使用 @Published 和 @StateObject 在 SwiftUI 中實現資料與 View 的同步。在練習過程中,我們使用到一個叫做 List 的元件來顯示清單,但還沒有詳細介紹 List 的用途和特性。今天,我們將進一步實作 List,將它整合到主畫面中,用來顯示我們的家用品清單。
List 是 SwiftUI 中一個非常常用的元件,有點像 UIKit 中的 UITableView,它被用來顯示一組資料的垂直列表。無論是顯示簡單的文字清單,還是建立複雜的自定義佈局,List 都能輕鬆應對。它內建了滾動和資料更新等功能,非常適合用來展示需要動態更新的資料清單。
List 也支援刪除、複選、多維資料顯示等功能,但由於我們尚未實作資料的異動,這部分會等待至之後再介紹。如果對這些進階功能有興趣,可以參考下方的資料來進一步了解!
我們將繼續使用昨天定義的 ItemViewModel,並在主畫面中使用 List 來顯示家用品的名稱和數量。我們回顧一下 ItemViewModel 的結構:
class ItemViewModel: ObservableObject {
@Published var items: [Item] = [
Item(name: "牛奶", quantity: 2),
Item(name: "麵包", quantity: 1)
]
func addItem(name: String, quantity: Int) {
let newItem = Item(name: name, quantity: quantity)
items.append(newItem)
}
}
接下來,我們在主畫面中使用 List 來顯示這些資料:
struct ContentView: View {
@StateObject var viewModel = ItemViewModel()
var body: some View {
List(viewModel.items) { item in
HStack {
Text(item.name)
.font(.headline)
Spacer()
Text("數量: \(item.quantity)")
.font(.subheadline)
.foregroundColor(.gray)
}
.padding(.vertical, 8)
}
}
}

List 來遍歷 viewModel.items,並將每個 Item 顯示為列表中的一行。List 會自動處理資料的佈局,並且當 items 發生變化時,自動更新列表顯示。HStack 來橫向排列物品的名稱和數量。這樣可以讓列表項目更加整齊有序。Spacer 用來在名稱和數量之間增加空間,讓它們對齊兩側。Text 來顯示物品名稱和數量,並使用不同的字型和顏色來區分它們。List 不僅能夠自動處理資料的顯示與佈局,還能夠在資料變動時自動更新,我們在 ItemViewModel 中使用了 @Published 屬性,這樣一來,當資料發生變化時,List 會立即顯示最新的內容,而不需要我們手動更新 UI。
除了 List,SwiftUI 還提供了其他元件來顯示列表或集合資料。這些元件各有不同的用途和優勢,可以根據不同的需求靈活選擇。
ForEach 通常與 VStack、HStack 或 ZStack 等元件結合使用,適合用來顯示靜態的佈局或不需要滾動的簡單列表。這種元件適合用在顯示少量固定的項目,或者在自訂 UI 佈局中嵌入多個子元件時使用。VStack {
ForEach(0..<5) { index in
Text("項目 \(index)")
}
}

參考資料:
.horizontal 或 .vertical 控制捲動的方向),常與 ForEach 結合使用。ScrollView 可以讓使用者滾動瀏覽內容。這個元件非常適合用來顯示長列表、圖片庫或其他需要滾動的資料。通常與 ForEach 或 LazyVStack 等元件結合使用。ScrollView {
VStack {
ForEach(0..<50) { index in
Text("項目 \(index)")
}
}
}

參考資料:
LazyVStack 和 LazyHStack 和 VStack 和 HStack 類似,但卻不同。不同於它們僅在需要時才載入內容,這對於顯示大量資料時能夠顯著提高效能。ScrollView {
LazyVStack {
ForEach(0..<100) { index in
Text("項目 \(index)")
}
}
}

ScrollView(.horizontal) {
LazyHStack(spacing: 16) {
ForEach(0..<100) { index in
Text("項目 \(index)")
.padding(.horizontal, 16)
.padding(.vertical, 8)
.background(Color.blue.opacity(0.7))
.foregroundColor(.white)
.cornerRadius(8)
}
}
.padding()
}

參考資料:
LazyVGrid 和 LazyHGrid 是用來顯示格狀佈局資料的元件,與 LazyVStack 和 LazyHStack 類似,會在使用時才載入內容。這些元件在大量資料顯示時具有更好的效能表現。LazyVGrid 和 LazyHGrid。它們能夠靈活處理格子的大小和佈局,適合展示需要多列或多行顯示的內容。let columns = [
GridItem(.flexible()),
GridItem(.flexible())
]
ScrollView {
LazyVGrid(columns: columns) {
ForEach(0..<50) { index in
Text("項目 \(index)")
}
}
}

let columns = [
GridItem(.fixed(50)),
GridItem(.fixed(50))
]
ScrollView(.horizontal) {
LazyHGrid(rows: columns, spacing: 16) {
ForEach(0..<50) { index in
Text("項目 \(index)")
}
}
}

參考資料:
Table 是專門用於 macOS 的元件,用來顯示表格式資料。struct Person: Identifiable {
let givenName: String
let familyName: String
let emailAddress: String
let id = UUID()
var fullName: String { givenName + " " + familyName }
}
@State private var people = [
Person(givenName: "Juan", familyName: "Chavez", emailAddress:
"juanchavez@icloud.com"),
Person(givenName: "Mei", familyName: "Chen", emailAddress: "meichen@icloud.com"),
Person(givenName: "Tom", familyName: "Clark", emailAddress: "tomclark@icloud.com"),
Person(givenName: "Gita", familyName: "Kumar", emailAddress: "gitakumar@icloud.com")
]
struct PeopleTable: View {
var body: some View {
Table(people) {
TableColumn("Given Name", value: \.givenName)
TableColumn("Family Name", value: \.familyName)
TableColumn("E-Mail Address", value: \.emailAddress)
}
}
}

今天我們認識 SwiftUI 中顯示列表的各種元件,尤其是 List 元件,並學習了如何使用它來顯示家用品清單。我們還簡單介紹其他幾個常用的列表元件,如 ForEach、ScrollView、LazyVStack 和 LazyVGrid,這些元件能夠幫助我們更靈活地處理不同類型的資料顯示需求。透過這些元件,我們能夠輕鬆創造出高效、美觀的 UI。
明天,我們將進一步學習如何在列表中新增與刪除項目,敬請期待!