最近在开发 瓦尔登 UI2.0 的笔记模块,这里记录一下遇到的问题和解决方案
问题:为什么在 Form 中使用 GeometryReader 时无法正确显示高度?
我们通常使用 GeometryReader 来获取 Container View 的尺寸,这在大多数情况下是可以正常使用的。但如果我们在 Form 中(或者 List、Scrollview 这类可滚动的 View)用到 GeometryReader 的同时又用到了 Lazy View,情况就会有点复杂,因为这类 View 的尺寸是动态变化的,导致的结果就是 View 的高度显示不正确(Form 表单的默认高度),如下图所示。
GeometryReader { proxy in
let width = proxy.size.width
let imageW = (width - 2 * 5) / 3
LazyVGrid(columns: noteImageCols, content: {
ForEach(note.imageArray) { image in
ImageView(image: image)
.frame(width: imageW, height: imageW)
}
})
}
可以看到,图片并没有显示完整(实际上有 4 张图)
解决方案:获取动态布局的尺寸
能否在 GeometryReader 获取高度来设定呢?答案是不行的
GeometryReader { proxy in
let width = proxy.size.width
let height = proxy.size.height // 这样是不行的 ❌
let imageW = (width - 2 * 5) / 3
LazyVGrid(columns: noteImageCols, content: {
ForEach(note.imageArray) { image in
ImageView(image: image)
.frame(width: imageW, height: imageW)
}
})
.frame(height: height) // 这样是不行的 ❌
}
但我们可以通过 LazyVGrid 的 background 这个 modifier 来获取真实的高度值,代码和效果如下
@State private var realHeight: CGFloat = 0 // 这样 OK ✅
GeometryReader { proxy in
let width = proxy.size.width
// let height = proxy.size.height // 这样是不行的 ❌
let imageW = (width - 2 * 5) / 3
LazyVGrid(columns: noteImageCols, content: {
ForEach(note.imageArray) { image in
ImageView(image: image)
.frame(width: imageW, height: imageW)
}
})
.background( GeometryReader { proxy2 -> Color in
let height = proxy2.size.height
realHeight = height
return .clear
}) // 这样 OK ✅
//.frame(height: height) // 这样是不行的 ❌
}
.frame(height: realHeight) // 这样 OK ✅
为什么通过 background 就能够获取正确的高度呢?因为 background 的尺寸大小是会着 View 的变化而变化的,因此在里面套一层 GeometryReader 就能够获得动态变化的尺寸大小