SwiftUI:检测NavigationView返回到主视图

3

我有一个NavigationView和以下的视图结构ViewA -> ViewB -> ViewC,我正在尝试找出如何检测当ViewB返回到ViewAViewB -> ViewA。这是我的代码:

struct ViewA: View {
    var body: some View {
        NavigationView {
            NavigationLink{
                ViewB()
            }label: {
                Text("Go to ViewB")
                
            }
        }
    }
}

struct ViewB: View {
    @Environment(\.presentationMode) var presentationMode: Binding
    var body: some View {
        NavigationLink{
            ViewC()
        }label: {
            Text("Go to ViewC")
        }
        .onAppear{
            print("onAppear \(presentationMode.wrappedValue.isPresented)")
        }
        .onDisappear{
            print("onDisappear \(presentationMode.wrappedValue.isPresented)")
        }
    }
}

struct ViewC: View {
    var body: some View {
        Text("ViewC")
    }
}

使用以下代码:

        .onAppear{
            print("onAppear \(presentationMode.wrappedValue.isPresented)")
        }
        .onDisappear{
            print("onDisappear \(presentationMode.wrappedValue.isPresented)")
        }

通过上述代码,我可以检测到当ViewC变为ViewB(根据控制台输出onAppear true)。但我的问题是如何检测ViewB -> ViewA的变化。

你们中是否有人知道如何完成这项任务或者是否有其他方法来检测这种变化?

非常感谢您的帮助。


2
为什么不在ViewA中像在ViewB中一样做呢?在ViewA中添加.onAppear{ print("----> onAppear ViewA") }.onDisappear{ print("----> onDisappear ViewA") }。从一个视图消失并出现在另一个视图中的组合应该可以让您确定从ViewBViewA。但请注意,NavigationView已被弃用,您应该使用NavigationStack,这将使所有这些变得更加容易。 - workingdog support Ukraine
3个回答

1

这里有一个基于新的NavigationStack的解决方案,它可以记录导航路径(正如@workingdog所提到的):

struct ViewA: View {
    
    @State private var navigationPath: [String] = []
    
    var body: some View {
        NavigationStack(path: $navigationPath) {
            NavigationLink(value: "B") {
                Text("Go to ViewB")
            }
            .navigationDestination(for: String.self) { destination in
                if destination == "B" {
                    ViewB()
                } else {
                    ViewC()
                }
            }
        }
        .onChange(of: navigationPath) { newValue in
            print(newValue)
            if newValue == [] {
                print("Coming from ViewB to ViewA") // trigger your action here
            }
        }
    }
}

struct ViewB: View {

    var body: some View {
        NavigationLink(value: "C") {
            Text("Go to ViewC")
        }
    }
}

struct ViewC: View {
    
    var body: some View {
        Text("ViewC")
    }
}

1

虽然这两种方法都是正确的,但@ChrisR提到的方法也很有效。如果我在处理这个问题,我会使用environmentObject,类似下面的方法。希望能对你有所帮助。已经在Xcode 14.3上测试通过。

class NavigationLinkDestination: ObservableObject {
    @Published var currentView: String = ""
}

struct ContentView: View {
    @StateObject var navigationLinkDest = NavigationLinkDestination()
    var body: some View {
        NavigationView {
            NavigationLink{
                ViewB()
            }label: {
                Text("Go to ViewB").onAppear {
                    navigationLinkDest.currentView = "ViewA"
                    print("current view \(navigationLinkDest.currentView)")
                }
                
            }
        }.environmentObject(navigationLinkDest)
    }
}

struct ViewB: View {
    @EnvironmentObject var navigationLinkDest: NavigationLinkDestination
    var body: some View {
        NavigationLink{
            ViewC()
        }label: {
            Text("Go to ViewC").onAppear {
                navigationLinkDest.currentView = "View B"
                print("current view \(navigationLinkDest.currentView)")
            }
        }.environmentObject(navigationLinkDest)
    }
}


struct ViewC: View {
    @EnvironmentObject var navigationLinkDest: NavigationLinkDestination
    var body: some View {
        Text("ViewC").onAppear {
            navigationLinkDest.currentView = "View C"
            print(navigationLinkDest.currentView)
        }.environmentObject(navigationLinkDest)
    }
}


0

如果您想要与 iOS 15 及更早版本兼容并继续使用 NavigationView,那么您可以通过使 ViewANavigationLink 的状态显式化来可靠地在 ViewB 弹出时得到通知。

您使用了 NavigationLink(destination:label:) 初始化程序,这意味着 NavigationLink 具有一个隐藏的标志,用于跟踪它是否处于活动状态。

相反,自己存储该标志,并使用自定义的 BindingNavigationLink(isActive:destination:label:) 初始化程序 一起使用,以便在 NavigationView 激活或停用链接时得到通知。

struct ViewA: View {
    @State var linkIsActive = false
    
    var body: some View {
        NavigationView {
            NavigationLink(isActive: Binding(
                get: { linkIsActive },
                set: {
                    if $0 != linkIsActive {
                        linkIsActive = $0
                        print($0 ? "pushing ViewB" : "popping ViewB")
                    }
                }
            )) {
                ViewB()
            } label: {
                Text("Go to ViewB")
            }
        }
        .navigationViewStyle(.stack)
    }
}

这是一个不错的东西! - ChrisR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接