List
视图是显示滚动数据行的好方法,但有时还需要数据列,能够在大屏上显示更多数据。这时就要用到 LazyHGrid
和 LazyVGrid
LazyHGrid
用于显示水平数据, LazyVGrid
用于显示垂直数据LazyHGrid
和 LazyVGrid
LazyHGrid
、LazyVGrid
仅仅支持 iOS 13 之后的系统版本定义网格布局有以下几种常用方法:
// 1.创建了3列网格,并让每一列具备精确宽度
let columns = [
GridItem(.fixed(80)),
GridItem(.fixed(80)),
GridItem(.fixed(80))
]
// 2.控制每个单元格最小宽度,在此基础上网格在每行中容纳尽可能多的项目,所以列数不定,只写一个即可
let columns = [
GridItem(.adaptive(minimum: 80))
]
// 3.使用 .flexible 精确控制列数(4列,那里面的单元格大小可以自适应)
let columns = [
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible()),
GridItem(.flexible())
]
// 4.结合起来使用:这将使第一列的宽度恰好为 100,第二列则会填充所有剩余空间
let columns = [
GridItem(.fixed(100)),
GridItem(.flexible()),
]
<aside>
💡 .flexible
用于自动调整列的宽度的大小,而 .adaptive
用于根据可用空间动态调整列的数量。根据具体的布局需求,你可以选择使用这两个选项中的一个来定义网格布局中的列。
</aside>
定义好布局后,应该将网格以及所需数量的项目放置在 ScrollView
内。您在网格中创建的每个项目都会自动分配一列,就像列表中的行自动放置在其父项中一样。我们只定义 LazyHGrid
和 LazyVGrid
两者中的一个,具体取决于想要哪种类型的网格。
// 定义垂直网格 LazyVGrid 时,参数是 columns
LazyVGrid(columns: layout, spacing: 20) {
ForEach(0..<100) {
Text("Item \\($0)")
}
}
// 定义水平网格 LazyHGrid 时,参数是 rows
LazyHGrid(rows: layout, alignment: .center) {
ForEach(0..<100) {
Text("Item \\($0)")
}
}
ScrollView {
LazyVGrid(columns: layout) {
ForEach(0..<1000) {
Text("Item \\($0)")
}
}
}
制作水平网格的过程几乎相同,您只需使 ScrollView
水平工作,然后使用行而不是列创建 LazyHGrid
:
ScrollView(.horizontal) {
LazyHGrid(rows: layout) {
ForEach(0..<1000) {
Text("Item \\($0)")
}
}
}
Grid
视图可以创建静态视图网格,并精确控制每行和每列的内容。您可以使用 GridRow
标记各个行,然后还可以配置每个单元格的宽度。
// 作为基本示例,这将创建一个 2x2 网格,其中的文本反映每个单元格的位置:
Grid {
GridRow {
Text("Top Leading")
.background(.red)
Text("Top Trailing")
.background(.orange)
}
GridRow {
Text("Bottom Leading")
.background(.green)
Text("Bottom Trailing")
.background(.blue)
}
}
如果您不想每行具有相同数量的单元格,有3种选择:
// 第1种方法:什么都不做,SwiftUI 将自动插入空单元格以确保 rows 相等
struct ContentView: View {
@State private var redScore = 0
@State private var blueScore = 0
var body: some View {
Grid {
GridRow {
Text("Red")
ForEach(0..<redScore, id: \\.self) { _ in
Rectangle()
.fill(.red)
.frame(width: 20, height: 20)
}
}
GridRow {
Text("Blue")
ForEach(0..<blueScore, id: \\.self) { _ in
Rectangle()
.fill(.blue)
.frame(width: 20, height: 20)
}
}
}
.font(.title)
Button("Add to Red") { redScore += 1 }
Button("Add to Blue") { blueScore += 1 }
}
}
// 第2个方法:是将视图放入网格中,而不将它们包装在 GridRow 中,这将导致它们自己占据整行。这对于 Divider 视图非常有用
// 第3个方法:是使用 gridCellColumns() 修饰符,使一个单元格跨越多个列
Grid {
GridRow {
Text("Food")
Text("$200")
}
GridRow {
Text("Rent")
Text("$800")
}
Divider()
GridRow {
Text("$4600")
.gridCellColumns(2)
.multilineTextAlignment(.trailing)
}
}
.font(.title)