LazyGrid分为LazyVGrid和LazyHGrid两种布局,但是用法都大同小异,这里就拿LzayVGrid来举例
LazyVGrid是SwiftUI中实现懒加载网格布局的强大工具。
它的主要作用有:
- 懒加载网格内容,避免一次性加载全部 Views导致性能问题
- 支持可变长和可变宽的网格布局
- 提供便捷的对齐、间距等布局配置方式
- 支持自适应不同尺寸的内容排布
下面是一个例子
struct LazyGridSample: View {
let columns = [
GridItem(.fixed(80))
]
var body: some View {
LazyVGrid(columns: columns) {
ForEach(0..<21) { index in
Rectangle()
.fill()
.frame(height: 80)
}
}
}
}
这里是循环了21个矩形,数据源是 columns , columns 的值有固定的要求,它是一个GridItem类型的数组。
上面代码会把21个矩形,按照一列的方式来排放,并且固定宽度为80。
GridItem 有三个参数,分别是size,spacing,alignment, 主要说说size参数,其他的两个参数前面的教程都有讲过。
Size 是一个枚举类型,默认是 .flexible()
// 方法定义
public init(_ size: GridItem.Size = .flexible(), spacing: CGFloat? = nil, alignment: Alignment? = nil)
// size 枚举值
public enum Size {
/// 具有指定固定大小的单个项目。
case fixed(CGFloat)
// 填充剩余空间
case flexible(minimum: CGFloat = 10, maximum: CGFloat = .infinity)
// 自适应最小大小
case adaptive(minimum: CGFloat, maximum: CGFloat = .infinity)
}
首先说说Size的第一个值 .fixed()
.fixed()
它的特点是以固定宽度来显示视图
我们稍微改造一下上面例子中的 columns 数组。
struct LazyGridSample: View {
let columns = [
GridItem(.fixed(80)),
GridItem(.fixed(120)),
GridItem(.fixed(80))
]
var body: some View {
LazyVGrid(columns: columns) {
ForEach(0..<21) { index in
Rectangle()
.fill()
.frame(height: 100)
}
}
}
}
现在是把21个矩形,按照三列来显示,左右两列的大小是固定大小为80,中间的固定宽度为120
.flexible()
它的特点是尽量占用剩余空间,这个很抽象,我们用例子来说明
我们把上面例子中的GridItem的size值变成 flexible 类型。来看看效果
struct LazyGridSample: View {
let columns = [
GridItem(.flexible())
]
var body: some View {
LazyVGrid(columns: columns) {
ForEach(0..<21) { index in
Rectangle()
.fill()
.frame(height: 100)
}
}
}
}
在这里它会尽量占用和屏幕一样宽的宽度,因为除了它本身视图以外,这一行没有其他试图,所以它会尽可能的占用剩余空间,所以就变成了一行
我们在稍加修改,把columns,变成三个GridItem,并且size的值都是尽量占用剩余空间的.flexible()值,下面就是效果,因为每个GridItem之间是有spacing的,所以会看到中间有空格,你可以把spacing设置为0。
我们可以看到上图,三个GridItem会平分一行,尽可能的占用剩余面积
如果上面的例子还不是太懂,可以看下面的例子
例子中,左边列是固定宽度为100,左边为flexible。它会尽可能大的占据整行除了左边100的部分
.adaptive()
大小将自动根据可用空间进行调整,这意味着它可以根据网格布局中的剩余空间动态调整大小,以填充可用空间,而不需要明确指定固定的大小
struct LazyGridSample: View {
let columns = [
GridItem(.adaptive(minimum: 50, maximum: 300))
]
var body: some View {
LazyVGrid(columns: columns) {
ForEach(0..<21) { index in
Rectangle()
.fill()
.frame(height: 50)
}
}
}
}
看下面的例子
struct LazyGridSample: View {
let columns = [
GridItem(.adaptive(minimum: 50, maximum: 300)),
GridItem(.adaptive(minimum: 150, maximum: 300))
]
var body: some View {
LazyVGrid(columns: columns) {
ForEach(0..<21) { index in
Rectangle()
.fill()
.frame(height: 50)
}
}
}
}
当我们变成两列时,第一列设置为最小宽度为50,第二列最小宽度为150时。它会把右边的三列变成一列,最小宽度为150,因为右边的距离只可以显示一个宽度为150的大小。所以只会显示一列
如果有兴趣你可以把上面的Columns的数据变成下面这样
let columns = [
GridItem(.adaptive(minimum: 10, maximum: 300)),
GridItem(.adaptive(minimum: 50, maximum: 300))
]
效果就变成下面这样了
在最后结束前,我会写一个和实际业务很类似的页面。来巩固一下前面提到的知识点。
以下是示例代码和效果图
struct LazyGridSample: View {
let columns = [ GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible()) ]
var body: some View {
ScrollView {
Rectangle()
.fill(Color.orange)
.frame(height: 250)
LazyVGrid(
columns: columns,
alignment: .center,
spacing: 6,
pinnedViews: [.sectionHeaders]
) {
Section {
ForEach(0..<19) { index in
Rectangle()
.fill()
.frame(height: 150)
}
} header: {
Text("Section 1")
.font(.title)
.foregroundColor(Color.white)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color.blue)
.padding()
}
Section {
ForEach(0..<49) { index in
Rectangle()
.fill(Color.purple)
.frame(height: 150)
}
} header: {
Text("Section 2")
.font(.title)
.foregroundColor(Color.white)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color.orange)
.padding()
}
}
}
}
}
以上效果很像一个照片瀑布流,例子里面有两个section,顶部是一个黄色矩形.其中LazyVGrid参数中的 PinnedViews需要说明一下
LazyVGrid(
columns: columns,
alignment: .center,
spacing: 6,
pinnedViews: [.sectionHeaders]
) {}
它接受一个PinnedScrollableViews类型数组参数,这里限定为我们使用的是一个sectoin视图,它的值限定为sectionFooters和sectionHeaders, 它的作用是,在视图滚动时,会固定住footer或者header,效果就是上图中的,section 2 会把 section 1 挤上去。
欢迎大家留言,也 Star 我的Github SwiftUI 系列教程