1

我有一个嵌套在 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
4

2 回答 2

1

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")
     }
}
于 2020-07-22T22:21:56.803 回答
0

我尝试在12.4 (12D4e)中运行 OP 的示例代码,但没有得到双重评估行为。启动时我得到:

Dimensions 1024.0, 1366.0
Dimensions 1024.0, 1220.0
GeometryReader appeared
Portrait appeared

并旋转 4 次(整圈):

Dimensions 1366.0, 878.0
Landscape appeared
Dimensions 1366.0, 898.0
Dimensions 1024.0, 1220.0
Portrait appeared
Dimensions 1366.0, 878.0
Landscape appeared
Dimensions 1366.0, 898.0
Dimensions 1024.0, 1220.0
Portrait appeared

对 ID 进行硬编码,例如.id("landscape"),不会影响行为,并且会从上面产生相同的打印语句。

为了避免在每次旋转时打印“出现纵向/横向”,我Text()从 if 语句中考虑:

GeometryReader { proxy in
    let text = self.showHorizontal(proxy.size.width, proxy.size.height) ? "Lanscape" : "Portrait"
    Text("\(text)")
        // .id(text)  // un-comment if you do want to see "Orientation appeared" w/every rotation
        .onAppear() {
            print("\(text) appeared")
        }
}
.onAppear() {
    print("GeometryReader appeared")
}

现在启动和一整圈的旋转产生:

Dimensions 1024.0, 1220.0
Portrait appeared
GeometryReader appeared
Dimensions 1366.0, 878.0
Dimensions 1366.0, 898.0
Dimensions 1024.0, 1220.0
Dimensions 1366.0, 878.0
Dimensions 1366.0, 898.0
Dimensions 1024.0, 1220.0
于 2021-04-03T20:23:46.077 回答