在SwiftUI中,使用NavigationView的GeometryReader在初始状态下会返回.zero大小。

3
我在NavigationView中使用了GeometryReader,但是当视图首次显示时,大小为0。我不确定这是否是一个bug或正确的行为,但我正在寻找一种解决方法,因为我的子视图没有正确地渲染。这个结构体演示了这个问题。下面的打印输出是:(0.0, 0.0)大小。有没有办法在初始显示时强制NavigationView提供正确的几何信息?
struct ContentView: View {
    var body: some View {
        NavigationView {
            GeometryReader { geometry in
                Text("Geometry Size Is Wrong")
                    .onAppear {
                        print(geometry.size)  // prints out (0.0, 0.0)
                    }
            }
        }
    }
}

3
如果你使用了.onChange(of: geometry.size) { ... },它会起作用。 - undefined
想想UIKit的viewDidLoad...通常情况下,第一次加载时框架是不正确的。就像你会在viewDidLayoutSubviews中修改框架一样,你可以按照@NewDev的建议,在.onChange中修改它们。 - undefined
我真的不太明白,我不只是想打印尺寸。我希望在第一次布局时正确地排列子视图。另外,我应该在哪里使用.onChange(of: geometry.size)?你能帮助我更好地理解这个工作原理吗?谢谢。 - undefined
1个回答

3

很遗憾,我认为在初始显示时,NavigationView无法提供正确的几何图形。

但是,如果您确实想要从视图内部访问最终的geometry.size,可以使用New Dev建议的onChange(of:)

struct ContentView: View {
  @State var currentSize: CGSize?

  var body: some View {
    NavigationView {
      GeometryReader { geometry in
        Text("currentSize will soon be correct")
          .onChange(of: geometry.size) { newSize in
            currentSize = newSize
            print(currentSize!) // prints (320.0, 457.0)
          }
      }
    }
  }
}

上述方案适用于大多数情况,但请注意,在GeometryReader的子视图中计算从geometry.size派生的任何本地变量在onChange块中将不准确(它将捕获原始错误值):

struct ContentView: View {
  @State var currentSize: CGSize?
  @State var halfWidth: CGFloat?

  var body: some View {
    NavigationView {
      GeometryReader { geometry in
        let halfWidthLocal = geometry.size.width / 2

        Text("Half Width is really: \(halfWidthLocal)") // will read as "Half Width is really 160.000000"
          .onChange(of: geometry.size) { newSize in
            currentSize = newSize
            halfWidth = halfWidthLocal
            print(currentSize!) // prints (320.0, 457.0)
            print(halfWidth!) // prints 0.0
          }
      }
    }
  }
}

为了使用最新版本的本地变量更新状态属性,您可以在返回视图的函数中更新属性,如下所示:

在GeometryReader中:

struct ContentView: View {
  @State var currentSize: CGSize?
  @State var halfWidth: CGFloat?

  var body: some View {
    NavigationView {
      GeometryReader { geometry in
        let halfWidthLocal = geometry.size.width / 2

        makeText(halfWidthLocal: halfWidthLocal)
          .onChange(of: geometry.size) { newSize in
            currentSize = newSize
            print(currentSize!) // prints (320.0, 457.0)
          }
      }
    }
  }

  func makeText(halfWidthLocal: CGFloat) -> some View {
    DispatchQueue.main.async { // Must update state properties on the main queue
      halfWidth = halfWidthLocal
      print(halfWidth!) // prints 0.0 the first time, then 160.0 the second time
    }
    return Text("Half Width is really: \(halfWidthLocal)") // will read as "Half Width is really 160.000000"
  }
}

我遇到了这种情况,所以想把这个知识传递给其他人。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接