I am using .sheet(isPresented: self.$showModal)
in my root view to present a modal. Within the modal, I am using NavigationView
to take the user through various pages (for a user profile builder).
In the last page of my navigation stack, I am using @Environment(\.presentationMode) var presentationMode
and a button which calls self.presentationMode.wrappedValue.dismiss()
to dismiss the modal. However, this only dismisses the last page in the navigation stack, and I just end up at the previous page. What I want to do is dismiss the entire navigation stack and end up back at the root view.
Swiping down to dismiss the modal produces the desired result, but I want to do this programatically with the button.
Is this currently possible in SwiftUI, or is this a problem with using NavigationView
within a modal sheet?
A possible solution is to use a custom EnvironmentKey
injected to every environment:
struct PresentationKey: EnvironmentKey {
static let defaultValue: [Binding<Bool>] = []
}
extension EnvironmentValues {
var presentations: [Binding<Bool>] {
get { return self[PresentationKey] }
set { self[PresentationKey] = newValue }
}
}
Demo:
struct ContentView: View {
@Environment(\.presentations) private var presentations
@State private var showSheet = false
var body: some View {
Button("Show sheet") {
showSheet = true
}
.sheet(isPresented: $showSheet) {
SheetView()
.environment(\.presentations, presentations + [$showSheet])
}
}
}
struct SheetView: View {
@Environment(\.presentations) private var presentations
@State private var showSheet = false
var body: some View {
Button("Show another sheet") {
showSheet = true
}
.sheet(isPresented: $showSheet) {
SheetNavigationView()
.environment(\.presentations, presentations + [$showSheet])
}
}
}
struct SheetNavigationView: View {
var body: some View {
NavigationView {
NavigationLink("Link", destination: SheetNavigationDetailView())
}
}
}
struct SheetNavigationDetailView: View {
@Environment(\.presentations) private var presentations
var body: some View {
Button("Pop to root") {
presentations.forEach {
$0.wrappedValue = false
}
}
}
}
struct SheetNavigationDetailView: View {
var body: some View {
Button("Pop to root") {
UIApplication.shared.windows.first?.rootViewController?.dismiss(animated: true)
}
}
}
You can pass showModal as a binding into the following screens and instead of using presentationValue set showModal to false.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With