[英]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.