首页 > 解决方案 > 为什么 GeometryReader 的主体会被评估两次?也是第一次尺寸为零?

问题描述

我有一个嵌套在 NavigationView 中的 GeometryReader。在 GeometryReader 内部,我使用 GeometryProxy 提供的尺寸和 if 语句。在我的项目中,我偶然发现了一个事实,即 GeometryReader 中的内容被评估了两次,并且第一次提供的尺寸是宽度 0 和高度 0。此外,if case 内的内容的 onAppear() 方法被调用两次,这会导致更多问题。

有人可以解释这种行为,以便我可以改进我的代码吗?

我做了一个最小的例子来展示这个问题:

import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationView() {
            NavigationLink(destination: SecondView()) {
                Text("Click me!")
            }
        }
        .navigationViewStyle(StackNavigationViewStyle())
    }
}

struct SecondView: View {
    private func showHorizontal(_ w: CGFloat, _ h: CGFloat) -> Bool {
        print("Dimensions \(w), \(h)")
        return (w > h)
    }
    
    var body: some View {
        GeometryReader { proxy in
            if self.showHorizontal(proxy.size.width, proxy.size.height) {
                Text("Landscape")
                .onAppear() {
                    print("Landscape appeared")
                }
            } else {
                Text("Portrait")
                .onAppear() {
                    print("Portrait appeared")
                }
            }
        }
        .onAppear() {
            print("GeometryReader appeared")
        }
    }
}

在横向的 iPad 上,我得到以下控制台输出:

Dimensions 0.0, 0.0
Dimensions 1194.0, 688.0
GeometryReader appeared
Landscape appeared
Landscape appeared

标签: iosswiftswiftuinavigationviewgeometryreader

解决方案


GeometryReader正在更新其几何形状的变化,这是有道理的。在您的 if 子句中,您正在为Text每个评估创建一个新视图。你所看到的是这些onAppear中的每一个。

if self.showHorizontal(proxy.size.width, proxy.size.height) {
         Text("Landscape")
         .onAppear() {
             print("Landscape appeared")
     }
}

如果出于某种原因需要 Text 保持不变,则可以使用id 修饰符为其分配一个 id ,如下所示:

if self.showHorizontal(proxy.size.width, proxy.size.height) {
         Text("Landscape")
         .id("fixed id")
         .onAppear() {
             print("Landscape appeared")
     }
}

推荐阅读