SwiftUI ScrollView VStack GeometryReader 高度被忽略 [英] SwiftUI ScrollView VStack GeometryReader height ignored

查看:54
本文介绍了SwiftUI ScrollView VStack GeometryReader 高度被忽略的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆