简体   繁体   English

SwiftUI:检测到 NavigationView 后退按钮按下

[英]SwiftUI: detecting the NavigationView back button press

In SwiftUI I couldn't find a way to detect when the user taps on the default back button of the navigation view when I am inside DetailView1 in this code:SwiftUI中,当我在这段代码中的DetailView1中时,我找不到一种方法来检测用户何时点击导航视图的默认后退按钮:

struct RootView: View {
    @State private var showDetails: Bool = false
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: DetailView1(), isActive: $showDetails) {
                    Text("show DetailView1")
                }
            }
            .navigationBarTitle("RootView")
        }
    }
}

struct DetailView1: View {
    @State private var showDetails: Bool = false
    var body: some View {
        NavigationLink(destination: DetailView2(), isActive: $showDetails) {
            Text("show DetailView2")
        }
        .navigationBarTitle("DetailView1")
    }
}

struct DetailView2: View {
    var body: some View {
        Text("")
            .navigationBarTitle("DetailView2")
    }
}

Using .onDisappear doesn't solve the problem as its closure is called when the view is popped off or a new view is pushed.使用.onDisappear并不能解决问题,因为在弹出视图或推送新视图时会调用它的闭包。

Following up on my comment, I would react to changes in the state of showDetails .跟进我的评论,我将对showDetails的 state 的更改做出反应。 Unfortunately didSet doesn't appear to trigger with @State variables.不幸的是didSet似乎没有用@State变量触发。 Instead, we can use an observable view model to hold the state, which does allow us to do intercept changes with didSet .相反,我们可以使用可观察视图 model 来保存 state,这确实允许我们使用didSet进行拦截更改。

struct RootView: View {
    class ViewModel: ObservableObject {
        @Published var showDetails = false {
            didSet {
                debugPrint(showDetails)
                // Maybe do something here?
            }
        }
    }
    @ObservedObject var viewModel = ViewModel()

    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: DetailView1(), isActive: $viewModel.showDetails) {
                    Text("show DetailView1")
                }
            }
            .navigationBarTitle("RootView")
        }
    }
}

An even nicer (SwiftUI-ier?) way of observing the published showDetails property:观察已发布的showDetails属性的更好(SwiftUI-ier?)方式:

struct RootView: View {
    class ViewModel: ObservableObject {
        @Published var showDetails = false
    }
    @ObservedObject var viewModel = ViewModel()

    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(destination: DetailView1(), isActive: $viewModel.showDetails) {
                    Text("show DetailView1")
                }
            }
            .navigationBarTitle("RootView")
            .onReceive(self.viewModel.$showDetails) { isShowing in
                debugPrint(isShowing)
                // Maybe do something here?
            }
        }
    }
}

The quick solution is to create a custom back button because right now the framework have not this possibility.快速的解决方案是创建一个自定义的后退按钮,因为现在框架没有这种可能性。

struct DetailView : View {

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

    var body : some View {
        Text("Detail View")
            .navigationBarBackButtonHidden(true)
            .navigationBarItems(leading: Button(action : {
                self.mode.wrappedValue.dismiss()
            }){
                Image(systemName: "arrow.left")
            })
    }
}

As soon as you press the back button, the view sets isPresented to false, so you can use an observer on that value to trigger code when the back button is pressed.按下后退按钮后,视图会将 isPresented 设置为 false,因此您可以在该值上使用观察者来在按下后退按钮时触发代码。 Assume this view is presented inside a navigation controller:假设此视图显示在导航 controller 中:

struct MyView: View {
    @Environment(\.isPresented) var isPresented

    var body: some View {
        Rectangle().onChange(of: isPresented) { newValue in
            if !newValue {
                print("detail view is dismissed")
            }
        }
    }
}
    

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM