SwiftUI ScrollView VStack GeometryReader 高度被忽略 [英] SwiftUI ScrollView VStack GeometryReader height ignored
问题描述
我想在 VStack 之外使用 ScrollView,以便在 VStack 扩展到超出屏幕尺寸时我的内容是可滚动的.现在我想在 VStack 中使用 GeometryReader
并且它会导致问题,我只能通过设置 GeometryReader 框架来解决这个问题,鉴于我使用阅读器来定义视图大小,这并没有真正帮助我.
I want to use a ScrollView outside of a VStack, so that my content is scrollable if the VStack expands beyond screen size.
Now I want to use GeometryReader
within the VStack and it causes problems, which I can only solve by setting the GeometryReader frame, which does not really help me given that I use the reader to define the view size.
这是没有 ScrollView 的代码,它运行良好:
Here is the code without a ScrollView and it works nicely:
struct MyExampleView: View {
var body: some View {
VStack {
Text("Top Label")
.background(Color.red)
GeometryReader { reader in
Text("Custom Sized Label")
.frame(width: reader.size.width, height: reader.size.width * 0.5)
.background(Color.green)
}
Text("Bottom Label")
.background(Color.blue)
}
.background(Color.yellow)
}
}
结果如下图:
自定义尺寸的标签应该是全宽,但高度是宽度的一半.现在,如果我将相同的代码包装在 ScrollView 中,就会发生这种情况:
The custom sized label should be full width, but half the width for height. Now if I wrap the same code in a ScrollView, this happens:
不仅所有东西都变小了,而且自定义尺寸标签的高度以某种方式被忽略了.如果我设置 GeometryReader 的高度,我可以调整该行为,但我希望 GeometryReader 增长到与其内容一样大.我怎样才能做到这一点?
Not just did everything get smaller, but the height of the Custom Sized Label is somehow ignored. If I set the height of the GeometryReader, I can adjust that behaviour, but I want to GeometryReader to grow as large as its content. How can I achieve this?
谢谢
推荐答案
应该理解 GeometryReader
并不是什么神奇的工具,它只是读取当前上下文父级中的可用空间,但是...ScrollView
没有自己的可用空间,它为零,因为它从内部内容确定所需的空间......所以使用 GeometryReader
在这里你有循环 - 孩子要求父母大小,但父级期望子级的大小......SwiftUI 渲染器以某种方式解决了这个问题(找到最小的已知大小),只是为了不崩溃.
It should be understood that GeometryReader
is not a magic tool, it just reads available space in current context parent, but... ScrollView
does not have own available space, it is zero, because it determines needed space from internal content... so using GeometryReader
here you have got cycle - child asks parent for size, but parent expects size from child... SwiftUI renderer somehow resolves this (finding minimal known sizes), just to not crash.
这里是您的场景的可能解决方案 - 此处适当的工具是查看首选项.准备和使用 Xcode 12/iOS 14 进行测试.
Here is possible solution for your scenario - the appropriate instrument here is view preferences. Prepared & tested with Xcode 12 / iOS 14.
struct DemoLayout_Previews: PreviewProvider {
static var previews: some View {
Group {
MyExampleView()
ScrollView { MyExampleView() }
}
}
}
struct MyExampleView: View {
@State private var height = CGFloat.zero
var body: some View {
VStack {
Text("Top Label")
.background(Color.red)
Text("Custom Sized Label")
.frame(maxWidth: .infinity)
.background(GeometryReader {
// store half of current width (which is screen-wide)
// in preference
Color.clear
.preference(key: ViewHeightKey.self,
value: $0.frame(in: .local).size.width / 2.0)
})
.onPreferenceChange(ViewHeightKey.self) {
// read value from preference in state
self.height = $0
}
.frame(height: height) // apply from stored state
.background(Color.green)
Text("Bottom Label")
.background(Color.blue)
}
.background(Color.yellow)
}
}
struct ViewHeightKey: PreferenceKey {
typealias Value = CGFloat
static var defaultValue = CGFloat.zero
static func reduce(value: inout Value, nextValue: () -> Value) {
value += nextValue()
}
}
注意:...如果您不确定视图所处的上下文,请不要使用 GeometryReader.
这篇关于SwiftUI ScrollView VStack GeometryReader 高度被忽略的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!