SwiftUI ScrollView VStack GeometryReader 高度被忽略
SwiftUI ScrollView VStack GeometryReader height ignored
我想在 VStack 之外使用 ScrollView,这样当 VStack 超出屏幕尺寸时我的内容是可滚动的。
现在我想在 VStack 中使用 GeometryReader
并且它会导致问题,我只能通过设置 GeometryReader 框架来解决,这并没有真正帮助我,因为我使用 reader 来定义视图大小.
这是没有 ScrollView 的代码,它运行良好:
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 中,就会发生这种情况:
不仅一切都变小了,而且自定义尺寸标签的高度也不知何故被忽略了。
如果我设置 GeometryReader 的高度,我可以调整该行为,但我希望 GeometryReader 增长到与其内容一样大。我怎样才能做到这一点?
谢谢
应该理解GeometryReader
不是神器,它只是在当前上下文parent中读取可用space,但是... ScrollView
不是有自己可用的 space,它是零,因为它从内部内容确定需要 space...所以在这里使用 GeometryReader
你有循环 - child 要求 parent 的大小,但 parent 期望大小来自 child...SwiftUI 渲染器以某种方式解决了这个问题(找到最小的已知大小),只是为了不崩溃。
以下是适用于您的情况的可能解决方案 - 此处合适的工具是查看首选项。使用 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: [=10=].frame(in: .local).size.width / 2.0)
})
.onPreferenceChange(ViewHeightKey.self) {
// read value from preference in state
self.height = [=10=]
}
.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。
我想在 VStack 之外使用 ScrollView,这样当 VStack 超出屏幕尺寸时我的内容是可滚动的。
现在我想在 VStack 中使用 GeometryReader
并且它会导致问题,我只能通过设置 GeometryReader 框架来解决,这并没有真正帮助我,因为我使用 reader 来定义视图大小.
这是没有 ScrollView 的代码,它运行良好:
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 中,就会发生这种情况:
不仅一切都变小了,而且自定义尺寸标签的高度也不知何故被忽略了。 如果我设置 GeometryReader 的高度,我可以调整该行为,但我希望 GeometryReader 增长到与其内容一样大。我怎样才能做到这一点?
谢谢
应该理解GeometryReader
不是神器,它只是在当前上下文parent中读取可用space,但是... ScrollView
不是有自己可用的 space,它是零,因为它从内部内容确定需要 space...所以在这里使用 GeometryReader
你有循环 - child 要求 parent 的大小,但 parent 期望大小来自 child...SwiftUI 渲染器以某种方式解决了这个问题(找到最小的已知大小),只是为了不崩溃。
以下是适用于您的情况的可能解决方案 - 此处合适的工具是查看首选项。使用 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: [=10=].frame(in: .local).size.width / 2.0)
})
.onPreferenceChange(ViewHeightKey.self) {
// read value from preference in state
self.height = [=10=]
}
.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。