2

In my an viewController I have this function

...{
let vc = UIHostingController(rootView: SwiftUIView())
        present(vc, animated: true, completion: nil)
}

Which present the following SwiftUIView.

Q How to dismiss the SwiftUIView when CustomButton pressed?

struct SwiftUIView : View {
     var body: some View {
       CustomButton()
     }   
}

struct CustomButton: View {

    var body: some View {
        Button(action: {
            self.buttonAction()
        }) {
            Text(buttonTitle)
        }
    }

    func buttonAction() {
        //dismiss the SwiftUIView when this button pressed
    }       
}
Mojtaba Hosseini
  • 47,708
  • 12
  • 157
  • 176
RyanTCB
  • 5,944
  • 3
  • 36
  • 55
  • 1
    Have you looked at this question? https://stackoverflow.com/questions/56819063/in-swiftui-how-to-use-uihostingcontroller-inside-an-uiview-or-as-an-uiview – dfd Aug 07 '19 at 17:48
  • You must define a @State and pass it to related **controlling** and **controlled by** views. – Mojtaba Hosseini Aug 08 '19 at 13:08
  • Following. If you haven't tried it yet—you can dismiss it by just dragging the controller down—but...I would certainly like to and am looking for a solution to dismiss on button pres. :) – ovatsug25 Aug 08 '19 at 13:31
  • @ovatsug25 yeah I need the button press because the .onDisappear callback doesn't fire when dragging to dismiss so need a defined action to perform some functions beforehand . – RyanTCB Aug 08 '19 at 13:34
  • Does this answer your question? [Dismiss a SwiftUI View that is contained in a UIHostingController](https://stackoverflow.com/questions/57190511/dismiss-a-swiftui-view-that-is-contained-in-a-uihostingcontroller) – Austin Conlon Dec 02 '20 at 02:17

1 Answers1

0
struct CustomButton: View {

    var body: some View {
        Button(action: {
            self.buttonAction()
        }) {
            Text(buttonTitle)
        }
    }

    func buttonAction() {
        if let topController = UIApplication.topViewController() {
            topController.dismiss(animated: true)
        }
    }       
}

extension UIApplication {
    class func topViewController(controller: UIViewController? = UIApplication.shared.windows.first { $0.isKeyWindow }?.rootViewController) -> UIViewController? {
        if let navigationController = controller as? UINavigationController {
            return topViewController(controller: navigationController.visibleViewController)
        }
        if let tabController = controller as? UITabBarController {
            if let selected = tabController.selectedViewController {
                return topViewController(controller: selected)
            }
        }
        if let presented = controller?.presentedViewController {
            return topViewController(controller: presented)
        }
        return controller
    }
}

Or if this doesn't work because you have a different view controller on top or if you need to use view life cycle events (onDisappear and onAppear won't work with UIHostingController). You can use instead:

final class SwiftUIViewController: UIHostingController<CustomButton> {
    required init?(coder: NSCoder) {
        super.init(coder: coder, rootView: CustomButton())
        rootView.dismiss = dismiss
    }
    
    init() {
        super.init(rootView: CustomButton())
        rootView.dismiss = dismiss
    }
    
    func dismiss() {
        dismiss(animated: true, completion: nil)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        rootView.prepareExit()
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        rootView.doExit()
    }
}

struct CustomButton: View {
    var dismiss: (() -> Void)?
    
    var body: some View {
        Button(action: dismiss! ) {
            Text("Dismiss")
        }
    }
    func prepareExit() {
        // code to execute on viewWillDisappear
    }
    func doExit() {
        // code to execute on viewDidDisappear
    }
}
Watermamal
  • 278
  • 1
  • 9
  • For me, this answer is giving an error as follows: Type 'UIApplication' has no member 'topViewController' – Doug Jul 05 '20 at 13:55
  • 1
    @Doug sorry I forgot I was using an extension, that will dismiss the top ViewController – Watermamal Jul 06 '20 at 17:36