I have rewritten my sign in view controller as a SwiftUI View
. The SignInView
is wrapped in a UIHostingController
subclass (final class SignInViewController: UIHostingController<SignInView> {}
), and is presented modally, full screen, when sign in is necessary.
Everything is working fine, except I can't figure out how to dismiss the SignInViewController
from the SignInView
. I have tried adding:
@Environment(\.isPresented) var isPresented
in SignInView
and assigning it to false
when sign in is successful, but this doesn't appear to interop with UIKit. How can I dismiss the view?
The alternate way to dismiss the screen is to use State/Binding variables. You present the screen on the current view using a State variable. Pass that state variable as a Binding variable to the next screen and attach the action that will toggle this binding variable.
When it comes time to dismiss a presented view controller, the preferred approach is to let the presenting view controller dismiss it. In other words, whenever possible, the same view controller that presented the view controller should also take responsibility for dismissing it.
Select the button that should make the UIViewController Disappear and drag it to the UIViewController you want to go to. In my case it shows **dismiss Controller* because of the name of my Class. Select it and you are done!
A UIKit view controller that manages a SwiftUI view hierarchy. Create a UIHostingController object when you want to integrate SwiftUI views into a UIKit view hierarchy.
However, when we use UIHostingController as the ViewController, the ability to swipe down to dismiss no longer works, for both Floating Modal and Full Screen. Even if I use UISwipeGestureRecognizer, it doesn’t get recognized, as the SwiftUI View is not the view that we have in code below, so no gesture will be captured.
You can use SwiftUI with UIKit very easily with the help of UIHostingController. Since UIKit does not speak SwiftUI, let’s introduce a mediator here, UIHostingController! UIHostingController creates a bridge between UIKit and SwiftUI framework. It works as a Container View for SwiftUI view, meaning you can use it as normal UIViewController.
Wrapping UIView or ViewController into SwiftUI is made easy with UIViewControllerRepresentable and UIViewRepresentable. Likewise, it is also possible to have SwiftUI View inside ViewController, by using UIHostingController. The official tutorial is here.
I found another approach that seems to work well and which feels a little cleaner than some of the other approaches. Steps:
dismissAction
property to the SwiftUI view:struct SettingsUIView: View { var dismissAction: (() -> Void) ... }
dismissAction
when you want to dismiss the view:Button(action: dismissAction ) { Text("Done") }
let settingsView = SettingsUIView(dismissAction: {self.dismiss( animated: true, completion: nil )}) let settingsViewController = UIHostingController(rootView: settingsView ) present( settingsViewController, animated: true )
UPDATE: From the release notes of iOS 15 beta 1:
isPresented, PresentationMode, and the new DismissAction action dismiss a hosting controller presented from UIKit. (52556186)
I ended up finding a much simpler solution than what was offered:
final class SettingsViewController: UIHostingController<SettingsView> { required init?(coder: NSCoder) { super.init(coder: coder, rootView: SettingsView()) rootView.dismiss = dismiss } func dismiss() { dismiss(animated: true, completion: nil) } } struct SettingsView: View { var dismiss: (() -> Void)? var body: some View { NavigationView { Form { Section { Button("Dimiss", action: dismiss!) } } .navigationBarTitle("Settings") } } }
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