iosswiftuidismissuihostingcontroller

How to dismiss SwiftUI View and also presenting SwiftUI View from one button in presented SwiftUI view


I have a swiftUI view that is presented using a hostingController:

let hostingController = UIHostingController(rootView: FirstView)
 someVC.present(hostingController, animated: true)

The FirstView in turn presents a second SwiftUI view using .sheet(IsPresented with a boolean to determine whether it should be displayed as follows:

struct FirstView: View {
    @Environment(\.presentationMode) var presentationMode

    @State var showSecondView = false
//change showSecondView to true so it displays as a sheet

 .sheet(isPresented: $showSecondView) {
                SecondView() 
            }
}

In SecondView, I have a button that I would like to use to dismiss both the SecondView and the FirstView as well. It dismisses the SecondView but I can't figure out how to dismiss the FirstView as well this since the FirstView was presented in a hosting controller not using a boolean.

If the SecondView was say an Alert within the First View, then I could use the environmental varialbe presentationMode to dismiss, however, that variable does not seem to be accessible from SecondView.

 struct SecondView: View {
        @Environment(\.dismiss) var dismiss
    
    
    Button("OK") {
//THIS DOES NOT WORK BECAUSE presentationMode is out of scope
                presentationMode.wrappedValue.dismiss()
  
                dismiss()//
            }
    }

How can I dismiss not only the current (or Second) sheet but also the presenting (or First view) which was presented in a hostingController.

Thanks in advance for any suggestions.


Solution

  • Sometimes you would pass an action closure, e.g.

     .sheet(isPresented: $showSecondView) {
        SecondView {
            showSecondView = false
        }
    }
    
    struct SecondView: View {
        let action: () -> ()
        
        ..    
    
        Button("OK") {
            action()
        }
    

    And sometimes the closure contains some data you want to pass back, e.g.

    struct SecondView: View {
        @State var text = ""
        let action: (String) -> ()
        
        ..    
    
        Button("OK") {
            action(text)
        }
    

    You can use the same technique to call back into UIKit when you init the root view for the hosting controller.