我在 NavigationView 中有一个 GeometryReader,当视图首次显示时,最初大小为 0。我不确定这是一个错误还是正确的行为,但我正在寻找一种方法来解决这个问题,因为我的子视图无法正确渲染。
这个结构演示了这个问题。
下面的打印输出是:(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)
}
}
}
}
}
不幸的是,我认为您无法做任何事情来使 NavigationView 在最初显示时提供正确的几何形状。
但是,如果您确实想从您的视图中访问最终的
geometry.size
,您可以按照新开发人员的建议使用 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
计算出的任何
local变量在
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"
}
}
这种情况发生在我身上,所以我只是想将知识传授给其他人。
导航堆栈内的视图最初以大小 0 渲染,然后立即以非零大小重新渲染。因为
.onAppear()
闭包只运行一次,所以你的代码只能看到零,而不是后续的实际大小值。在 SwiftUI 中,由于多种原因多次渲染视图是很常见的。
但是您可以等待在
GeometryReader
内渲染视图,直到几何图形非零。因此,在几何形状良好或至少非零(*)之前,您的 .onAppear()
根本不会运行。只需在 geometry.size != .zero
上绘制您的视图即可
对于您的示例代码,可能如下所示:
struct ContentView: View {
var body: some View {
NavigationView {
GeometryReader { geometry in
if geometry.size != .zero {
Text("Geometry Size Is \(geometry.size.width) x \(geometry.size.height)")
.onAppear {
print(geometry.size) // prints out a nonzero size
}
}
}
}
}
}
(*) 警告:如果您向导航过渡添加动画,这可能不会/不会为您提供最终的几何图形,因为您的视图将以各种尺寸绘制许多次。