swift - SwiftUI 应用程序的 NavigationView 中的 onAppear 和 onDisappear 是否按预期运行?

标签 swift swiftui ios-navigationview

我想知道 SwiftUI(我写这篇文章时是 Xcode 11 beta 6)中 onAppear 和 onDisappear 的行为是开发人员会觉得更有用的,还是只是一个问题而不是一个功能。

现在,如果我们使用级联导航,正如您将在我附加的示例代码中找到的那样(在 Xcode 11b6 中编译和运行良好),用户来回导航的控制台输出只会触发 onAppear向前方向(意味着更深入)的新 View 负载的情况。

在导航中: 根 -> NestedView1 -> NestedView2 -> NestedView3 , 向每个 View 阶段添加调试助手时,

  .onAppear(perform: {print("onAppear level N")})
  .onDisappear(perform: {print("onDisappear level N")})

调试控制台会显示

onAppear root level 0
onAppear level 1
onAppear level 2
onAppear level 3

(无 onDisappear 触发)

但回程 根 <- NestedView1 <- NestedView2 <- NestedView3

调试控制台会显示...什么都没有

(无 onAppear 或 onDisappear 触发)

struct NestedViewLevel3: View {

    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

    var body: some View {
        VStack {
            Spacer()
            Text("Level 3")
            Spacer()
            Button(action: {
                self.presentationMode.wrappedValue.dismiss()
            }) {
                Text("Back")
                    .padding(.horizontal, 15)
                    .padding(.vertical, 2)
                    .foregroundColor(Color.white)
                    .clipped(antialiased: true)
                    .background(
                        RoundedRectangle(cornerRadius: 20)
                            .foregroundColor(Color.blue)
                            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
                )
            }
            Spacer()
        }
        .navigationBarBackButtonHidden(false)
        .navigationBarTitle("Level 3", displayMode: .inline)
        .onAppear(perform: {print("onAppear level 3")})
        .onDisappear(perform: {print("onDisappear level 3")})

    }
}

struct NestedViewLevel2: View {

    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

    var body: some View {
        VStack {
            Spacer()
            NavigationLink(destination: NestedViewLevel3()) {
                Text("To level 3")
                    .padding(.horizontal, 15)
                    .padding(.vertical, 2)
                    .foregroundColor(Color.white)
                    .clipped(antialiased: true)
                    .background(
                        RoundedRectangle(cornerRadius: 20)
                            .foregroundColor(Color.gray)
                            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
                )
                    .shadow(radius: 10)
            }
            Spacer()
            Text("Level 2")
            Spacer()
            Button(action: {
                self.presentationMode.wrappedValue.dismiss()
            }) {
                Text("Back")
                    .padding(.horizontal, 15)
                    .padding(.vertical, 2)
                    .foregroundColor(Color.white)
                    .clipped(antialiased: true)
                    .background(
                        RoundedRectangle(cornerRadius: 20)
                            .foregroundColor(Color.blue)
                            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
                )
            }
            Spacer()
        }
        .navigationBarBackButtonHidden(false)
        .navigationBarTitle("Level 2", displayMode: .inline)
        .onAppear(perform: {print("onAppear level 2")})
        .onDisappear(perform: {print("onDisappear level 2")})
    }
}

struct NestedViewLevel1: View {

    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

    var body: some View {
        VStack {
            Spacer()
            NavigationLink(destination: NestedViewLevel2()) {
                Text("To level 2")
                    .padding(.horizontal, 15)
                    .padding(.vertical, 2)
                    .foregroundColor(Color.white)
                    .clipped(antialiased: true)
                    .background(
                        RoundedRectangle(cornerRadius: 20)
                            .foregroundColor(Color.gray)
                            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
                )
                    .shadow(radius: 10)
            }
            Spacer()
            Text("Level 1")
            Spacer()
            Button(action: {
                self.presentationMode.wrappedValue.dismiss()
            }) {
                Text("Back")
                    .padding(.horizontal, 15)
                    .padding(.vertical, 2)
                    .foregroundColor(Color.white)
                    .clipped(antialiased: true)
                    .background(
                        RoundedRectangle(cornerRadius: 20)
                            .foregroundColor(Color.blue)
                            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
                )
            }
            Spacer()
        }
        .navigationBarBackButtonHidden(false)
        .navigationBarTitle("Level 1", displayMode: .inline)
        .onAppear(perform: {print("onAppear level 1")})
        .onDisappear(perform: {print("onDisappear level 1")})
    }
}

struct RootViewLevel0: View {

    var body: some View {
        NavigationView {
        VStack {
            Spacer()
            NavigationLink(destination: NestedViewLevel1()) {
            Text("To level 1")
                .padding(.horizontal, 15)
                .padding(.vertical, 2)
                .foregroundColor(Color.white)
                .clipped(antialiased: true)
                .background(
                    RoundedRectangle(cornerRadius: 20)
                    .foregroundColor(Color.gray)
                    .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 40, alignment: .center)
                )
                .shadow(radius: 10)
        }

            Spacer()

            }
    }

        .navigationBarTitle("Root level 0", displayMode: .inline)
        .navigationBarBackButtonHidden(false)
        .navigationViewStyle(StackNavigationViewStyle())
        .onAppear(perform: {print("onAppear root level 0")})
        .onDisappear(perform: {print("onDisappear root level 0")})

    }

}


struct ContentView: View {
    var body: some View {
        RootViewLevel0()
    }
}


}

现在,开发人员宁愿使用 onAppear 和 onDisappear:

1) 触发的目的是启动只需要执行一次且仅当用户向前移动时才需要执行的操作,就像在当前观察到的行为中一样。

2) 每次 View 出现时触发,更像是 Action 名称的意思,无论是向后、向前还是任意次数。

我会选择选项 2,简单而粗暴(也是我目前需要的),但我是 NavigationView 的一个相当天真的新手,选项 2 可能会打破很多我没有考虑到的既定范例。

您的反馈将帮助我确定相应的 SwiftUI 反馈助手案例是否具有合法依据。

最佳答案

这是 Apple 端的一个错误。

.onAppear() 现在可以在 iOS 13.1 和 Xcode 11 Beta 7 中正常工作。

当向前和向后导航到 NavigationView 时,.onAppear() 将被触发。

关于swift - SwiftUI 应用程序的 NavigationView 中的 onAppear 和 onDisappear 是否按预期运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57661962/

相关文章:

ios - SWIFT:NSURLSession 将数据转换为字符串

ios - 在 MapView 上渲染多条折线

swift - NSPredicate 用于搜索带双引号的字符串

ios - 当我的基于 SwiftUI 的应用程序以横向模式启动时,导航栏上的背景颜色未设置

ios - SwiftUI 使用导航链接从模态表过渡到常规 View

ios - 使用 Swift 和 Realm 的单向数据流的对象 View 状态

swift - SwiftUI 中文本内的居中对齐文本

ios - Xcode Beta 6 中的 SwiftUI 模式?

ios - 创建与 PPT 通信所需的 CFMessagePort 时出错

swift - 如何使用 UINavigationController 的 searchController 属性将 UISearchController 合并到 SwiftUI NavigationView 中?