SwiftUI ScrollView 不计算自定义 StaggeredGrid 高度
Posted
技术标签:
【中文标题】SwiftUI ScrollView 不计算自定义 StaggeredGrid 高度【英文标题】:SwiftUI ScrollView doesn't compute custom StaggeredGrid height 【发布时间】:2021-05-27 14:01:15 【问题描述】:我正在尝试在 SwiftUI 中创建一个新的网格结构来显示具有可变高度的卡片。在这个程度上,我在HStack
中使用了几个LazyVStack
s,并且有条件以正确的顺序显示我的数据项。这个视图单独工作,使列数适应屏幕的大小,但是当在ScrollView
中使用它时,它的大小计算不正确,以下视图最终位于网格下方而不是网格下方。这是我用于网格的代码:
struct StaggeredGrid<Element, Content>: View where Content: View
var preferredItemWidth: CGFloat
var data: [Element] = []
var content: (Element) -> Content
init(preferredItemWidth: CGFloat, data: [Element], @ViewBuilder content: @escaping (Element) -> Content)
self.preferredItemWidth = preferredItemWidth
self.data = data
self.content = content
var body: some View
GeometryReader geometry in
HStack(alignment: .top, spacing: 20)
ForEach(1...Int(geometry.size.width / preferredItemWidth), id: \.self) number in
LazyVStack(spacing: 20)
ForEach(0..<data.count, id: \.self) index in
if (index+1) % Int(geometry.size.width / preferredItemWidth) == number % Int(geometry.size.width / preferredItemWidth)
content(data[index])
.padding([.horizontal])
以及显示行为的预览:
struct StaggeredGrid_Previews: PreviewProvider
static var previews: some View
ScrollView
VStack
StaggeredGrid(preferredItemWidth: 160, data: (1...10).map"Item \($0)") item in
Text(item)
.foregroundColor(.blue)
Text("I should be below the grid")
这是预览图: Wrong appearance in a ScrollView
还有一张ScrollView
被注释掉的图片:
Expected behavior, ScrollView removed
提前感谢您提供有关我不理解的这种行为的任何帮助或线索。
【问题讨论】:
【参考方案1】:我引用 @Asperi : “ScrollView 没有自己的大小,GeometryReader 没有自己的大小,所以你遇到了鸡蛋问题,即没有人知道要渲染的大小,所以折叠了。你必须为 ScrollView 中的项目有明确的框架大小。”
在这里您必须设置StaggeredGrid
的高度,或者它包含的GeometryReader
。
在您的情况下,它的高度当然取决于其内容的高度(即 HStack)。您可以使用 Reader 读取此高度(例如其背景/叠加层的高度)。并用它来确定 GeometryReader 的帧大小
例如:
struct StaggeredGrid<Element, Content>: View where Content: View
var preferredItemWidth: CGFloat
var data: [Element] = []
var content: (Element) -> Content
init(preferredItemWidth: CGFloat, data: [Element], @ViewBuilder content: @escaping (Element) -> Content)
self.preferredItemWidth = preferredItemWidth
self.data = data
self.content = content
@State private var gridHeight: CGFloat = 100
var body: some View
GeometryReader geometry in
HStack(alignment: .top, spacing: 20)
ForEach(1...Int(geometry.size.width / preferredItemWidth), id: \.self) number in
LazyVStack(spacing: 20)
ForEach(0..<data.count, id: \.self) index in
if (index+1) % Int(geometry.size.width / preferredItemWidth) == number % Int(geometry.size.width / preferredItemWidth)
content(data[index])
.overlay(GeometryReader proxy in
Color.clear.preference(
key: HeightPreferenceKey.self,
value: proxy.size.height
)
)
.onPreferenceChange(HeightPreferenceKey.self)
gridHeight = $0
.padding([.horizontal])
.frame(height: gridHeight)
private struct HeightPreferenceKey: PreferenceKey
static let defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat,
nextValue: () -> CGFloat)
value = nextValue()
【讨论】:
使用 PreferenceKey 修复了我的网格,非常感谢!以上是关于SwiftUI ScrollView 不计算自定义 StaggeredGrid 高度的主要内容,如果未能解决你的问题,请参考以下文章
Swiftui Scrollview Viewmodifier 适用于所有 Scrollview
在 ScrollView 中使用 GeometryReader 的 SwiftUI 布局
ScrollView 行为怪异(Xcode 11 GM 种子 - SwiftUI)
SwiftUI - 计算 ScrollView 中长 GeometryReader 的高度