DanielRM
DanielRM

Reputation: 666

Dismiss SwiftUI View back to a UIKit ViewController

Would like to return to my presenting UIKit View Controller after pressing the save button on my SwiftUI View (presented via a HostingViewController).
This is how a navigate to my SwiftUI view from my UIKit VC.

let profileView = suiProfileView().environmentObject(suiProfileViewModel())
            let profileVC = UIHostingController(rootView: profileView)
            let navVC = UINavigationController(rootViewController: profileVC)
            navVC.modalPresentationStyle = .fullScreen
            SideMenuManager.default.leftMenuNavigationController?.present(navVC, animated: true , completion: nil)

This is my SwiftUI View that i'd like to dismiss after pressing the Save button

import SwiftUI
import Combine

struct suiProfileView: View {
    @SwiftUI.Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
    @EnvironmentObject var profileViewModel: suiProfileViewModel
    
    @State var suiTitleText = t("general.save")
    
    var body: some View {
        GeometryReader { geo in
            VStack {
                personalInfoSection
                Spacer()
                Button("Save", action: profileViewModel.saveProfile)
                    .frame(width: geo.size.width * 0.8, height: geo.size.height * 0.08, alignment: .center)
            }
            .onReceive(profileViewModel.viewDismissalModePublisher) { shouldDismiss in
                if shouldDismiss {
                    self.presentationMode.wrappedValue.dismiss()
                }
            }
            .frame(width: geo.size.width, height: geo.size.height, alignment: .center)
            .padding()
        }
    }
}

This is my ProfileViewModel class which publishes the shouldDismissView variable using Combine after running some business logic.

class suiProfileViewModel: suiProfileViewModelProtocol {

    //private var model: suiProfileFormProtocol
    @Published var profile = suiProfileForm()
    
    var viewDismissalModePublisher = PassthroughSubject<Bool, Never>()
    private var shouldDismissView = false {
        didSet {
            viewDismissalModePublisher.send(shouldDismissView)
        }
    }
    
    func businessLogicThatDeterminesIfShouldDismissView() {
        //....
    }
}

For some reason self.presentationMode.wrappedValue.dismiss() which was called in my SwiftUI view is not dismissing my SwiftUI view and not allowing me to go back to my initial UIKit View Controller who presented it in the first place. Any help would greatly appreciated. Thanks in advance

Upvotes: 5

Views: 2369

Answers (1)

jnpdx
jnpdx

Reputation: 52426

A couple problems that I see:

  1. You're trying to dismiss your suiProfileView , but really, it's wrapped in a UINavigationController before you present it.

  2. According to a basic test that I just did, even if your suiProfileView were presented without the navigation controller, presentationMode still doesn't work on it -- my suspicion is that it's only passed accurately when going SwiftUI->SwiftUI and can't be trusted to be communicated through the UIHostingController

I would suggest passing a closure to suiProfileView that can run the dismiss code from your original presenting view controller. Here's a simplified example:


import UIKit
import SwiftUI

class ViewController: UIViewController {

    var presentedController : UINavigationController?
    
    func dismissVC() {
        presentedController?.dismiss(animated: true)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            let swiftUIView = ContentView(dismiss: self.dismissVC)
            let hostVC = UIHostingController(rootView: swiftUIView)
            let navVC = UINavigationController(rootViewController: hostVC)
            navVC.modalPresentationStyle = .fullScreen
            self.present(navVC, animated: true , completion: nil)
            self.presentedController = navVC
        }
        
    }
}


struct ContentView : View {
    var dismiss : () -> Void
    
    @Environment(\.presentationMode) private var presentationMode: Binding<PresentationMode>
    
    var body: some View {
        Button(action: {
            dismiss()
            //presentationMode.wrappedValue.dismiss() <-- doesn't function
        }) {
            Text("Close")
        }
    }
}

Upvotes: 7

Related Questions