Reputation: 5475
On iOS 14 and earlier, we import the presentationMode
environment variable:
@Environment(\.presentationMode) var presentationMode
and then call self.presentationMode.wrappedValue.dismiss()
to dismiss the view.
This has been deprecated on iOS 15, and a new environment variable, dismiss
, is introduced:
@Environment(\.dismiss) var dismiss
which we can call directly using dismiss()
to achieve the same.
I know we can do the following to call the appropriate dismiss function and support all versions:
if #available(iOS 15, *) {
self.dismiss()
} else {
self.presentationMode.wrappedValue.dismiss()
}
But how do I import/define the right environment variable? As trying this doesn't work:
if #available(iOS 15, *) {
@Environment(\.dismiss) var dismiss
} else {
@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
}
Edit:
Apparently using presentationMode
to dismiss a view in a Navigation stack still works on iOS 15 Beta 4. Unless there is a TabView inside the NavigationView:
struct ContentView: View {
var body: some View {
NavigationView {
TabView {
NavigationLink(destination: ChildView()) {
Text("View Child")
}
}
}
}
}
struct ChildView: View {
@Environment(\.presentationMode) var presentationMode
var body: some View {
Button(action: {
print("Popping...")
self.presentationMode.wrappedValue.dismiss()
}, label: {
Text("POP")
.font(.headline)
})
}
}
presentatinMode
doesn't work in this case.
Upvotes: 16
Views: 5685
Reputation: 33
You can use this:
@Environment(\.dismiss) var dismiss
and here is the source.
Upvotes: -2
Reputation: 431
Since I don't like "just use deprecated stuff cause it works" approach I was looking for an answer on this matter as well.
The best solution I could come up so far which doesn't require too much code change as well and uses DismissAction
when available is this:
extension EnvironmentValues {
// this can be used as: @Environment(\.dismissable) var myDismiss
// in any swiftui view and it will not complain about ios versions
var dismissable: () -> Void {
return dismissAction
}
// this function abstracts the availability check so you can
// avoid the conflicting return types and any other headache
private func dismissAction() {
if #available(iOS 15, *) {
dismiss()
} else {
presentationMode.wrappedValue.dismiss()
}
}
}
just in case anyone's unclear with the usage of this new environment value here is an example (some parts, like navigation or presenting are ommited):
// view inside navigation/sheet
struct SomeInnerView: View {
@Environment(\.dismissable) var myDismiss
var body: some View {
VStack {
Button("dismiss me way 1") { myDismiss() } // tapping will result in a dismissing of this view
Button("dismiss me way 2", action: myDismiss) // p.s this was not directly possible with DismissAction
}
}
}
Upvotes: 3
Reputation: 571
To support dismiss and iOS 14 add this extension to your EnvironmentValues
@available(iOS 14.0, *)
extension EnvironmentValues {
var dismiss: () -> Void {
{ presentationMode.wrappedValue.dismiss() }
}
}
Upvotes: 10
Reputation: 3259
I know this apple not yet fix the bug in SwiftUI. So far I am following the below approach it will work for me all the versions. Might be it will helpful for your situation
//presentationMode.wrappedValue.dismiss()
if var topController = UIApplication.shared.windows.first!.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
topController.dismiss(animated: true)
}
Upvotes: 3