【问题标题】:Why is the body of a GeometryReader evaluated twice? Also first time with dimensions of zero?为什么 GeometryReader 的主体会被评估两次?也是第一次尺寸为零?
【发布时间】:2020-07-22 22:10:54
【问题描述】:

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

【问题讨论】:

  • 看起来它会根据几何形状的变化进行更新,这是有道理的。

标签: ios swift swiftui navigationview geometryreader


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

    我尝试在 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多