SwiftUI 4.0 引入了一個新的 Grid
API 來組成基於網格的佈局。 你可以使用 VStack
和 HStack
安排相同的佈局。 然而,Grid
視圖使其變得容易得多。 Grid
視圖是一種容器視圖,它以二維佈局排列其他視圖。
讓我們從一個簡單的網格開始。 要創建一個 2x2 網格,你可以編寫如下程式碼:
struct ContentView: View {
var body: some View {
Grid {
GridRow {
Color.purple
Color.orange
}
GridRow {
Color.green
Color.yellow
}
}
}
}
假設你已經在 Xcode 中創建了一個 SwiftUI 項目,你應該會看到一個 2x2 的網格,其中填上了不同的顏色。
要建立 3x3 網格,你只需添加另一個 GridRow
。 並且,對於每個GridRow
,再插入一個子視圖。
比較網格視圖和堆棧視圖
為什麼我們需要使用 Grid
API? 我們其實可以使用 HStack
和 VStack
創建相同的網格 UI。 那麼,蘋果為什麼要引入這個新的 API? 對!你可以使用堆棧視圖構建相同的網格。 然而,有一個主要的區別使得 Grid
視圖在構建網格佈局時更受歡迎。
讓我們使用下面的程式碼創建另一個 2x2 網格:
struct ContentView: View {
var body: some View {
Grid {
GridRow {
Image(systemName: "trash")
.font(.system(size: 100))
Image(systemName: "trash")
.font(.system(size: 50))
}
GridRow {
Color.green
Color.yellow
}
}
}
}
這次,第一行顯示兩個系統圖像,第二行顯示彩色視圖。 你的預覽應顯示如下所示的網格。
要使用嵌套的VStack
和HStack
構建相同的網格佈局,我們可以編寫如下程式碼:
VStack {
HStack {
Image(systemName: "trash")
.font(.system(size: 100))
.frame(minWidth: 0, maxWidth: .infinity)
Image(systemName: "trash")
.font(.system(size: 50))
.frame(minWidth: 0, maxWidth: .infinity)
}
HStack {
Color.green
Color.yellow
}
}
在預設的情況下,Grid
視圖的每一列在一行中佔據相等的空間。 但對於 HStack
,我們必須附加 frame
修飾器以使每張圖像在行中佔據相同的空間。
Grid
視圖只是讓創建網格視圖變得更容易,並提供了幾個修改器來自定義網格佈局。
使用 gridCellColumns 合併單元格
創建網格視圖時,你可能希望在特定行中顯示單個單元格,而其他行繼續顯示多個單元格。 gridCellColumns
修飾器專為你合併單元格而設計。 這是一個例子:
Grid {
GridRow {
Image(systemName: "trash")
.font(.system(size: 100))
Image(systemName: "trash")
.font(.system(size: 50))
}
GridRow {
Color.purple
.overlay {
Image(systemName: "magazine.fill")
.font(.system(size: 100))
.foregroundColor(.white)
}
.gridCellColumns(2)
}
}
第二行只有一個單元格。 我們附加 gridCellColumn
修飾器並將其值設置為 2
以合併單元格。 如果你不使用修飾器,就會看到一個空白單元格。
添加空白單元格
現在讓我們像這樣創建另一個 3x3 網格視圖:
struct ContentView: View {
var body: some View {
Grid {
GridRow {
IconView(name: "cloud")
IconView(name: "cloud")
IconView(name: "cloud")
}
GridRow {
IconView(name: "cloud")
IconView(name: "cloud")
IconView(name: "cloud")
}
GridRow {
IconView(name: "cloud")
IconView(name: "cloud")
IconView(name: "cloud")
}
}
}
}
struct IconView: View {
var name: String = "trash"
var body: some View {
Image(systemName: name)
.frame(width: 100, height: 100)
.background(in: Rectangle())
.backgroundStyle(.purple)
.foregroundStyle(.white.shadow(.drop(radius: 1, y: 3.0)))
.font(.system(size: 50))
}
}
如果我們想為網格中心的單元格顯示一個空白視圖怎麼辦? 為此,你可以使用以下程式碼添加一個空白單元格:
Color.clear
.gridCellUnsizedAxes([.horizontal, .vertical])
如果用上面的程式碼替換中心單元格,你將在網格中心看到一個空白單元格。
gridCellUnsizedAxes
修飾器可防止空白單元格佔用的空間超過行或列中其他單元格所需的空間。 如果省略修飾器,就會出現如圖 7 所示的網格佈局。
調整單元格間距
要控制單元格之間的垂直和水平間距,你可以在建立 Grid
視圖時使用 horizontalSpacing
和 verticalSpacing
參數:
Grid(horizontalSpacing: 0, verticalSpacing: 0) {
.
.
.
}
如果需要在行之間添加一些間距,可以將 padding
修飾器附加到 GridRow
。 下圖是一個示例:
控制單元對齊
Grid
視圖有一個名為 alignment
的參數,供你配置單元格的預設對齊方式。 例如,此處將對齊方式設置為 .bottom :
Grid(alignment: .bottom, horizontalSpacing: 0, verticalSpacing: 0) {
.
.
.
}
如果你更改了程式碼,黑框應與單元格底部就會對齊。
要更改預設對齊設置,單元格本身可以附加 gridCellAnchor
修飾器來更改對齊方式。 下圖是一個例子:
總結
Grid
API 為開發人員提供了構建基於網格的佈局的更多選項。 你可以使用HStack
和VStack
來構建類似的佈局。 但是 Grid
視圖可以為你節省大量代碼並使你的程式碼更具可讀性。 如果你的App只需要支持最新版本的 iOS,可以嘗試使用 Grid
API 來構建一些有趣的佈局。