How to fix navigation controller constraints when loading SwiftUI from UIKit

Considering you use a UIKit app as shown below.

When you load a SwiftUI view from UIKit you would use a hosting controller to load. At this instance, most likely you will see a small gap at the top. This happens because of the conflict between the navigation controllers of UIKit and SwiftUI.

let paymentVC = UIHostingController(rootView: WireCountrySelectorSwiftUIView())
self.navigationController?.pushViewController(paymentVC, animated: true)

To fix this you can do the following. Add a view controller in the middle, and set the hosting controllers constraints inside that controller. Here is a example on how to do that

@objc public class MiddleHostingControllerVC: UIViewController {
    
    @objc public override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = .clear
        let wireOptionsSelectionView = LoadSwiftUIView()
        let hostingController = UIHostingController(rootView: wireOptionsSelectionView)
        hostingController.view.backgroundColor = .white
        self.view.layoutIfNeeded()
        self.addChild(hostingController)
        self.view .addSubview(hostingController.view)
        hostingController.view.translatesAutoresizingMaskIntoConstraints = false
        
        self.view.addConstraint(NSLayoutConstraint(item: hostingController.view!, attribute: NSLayoutConstraint.Attribute.leading, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.leading, multiplier: 1.0, constant: 0.0))
        self.view.addConstraint(NSLayoutConstraint(item: hostingController.view!, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1.0, constant: 0.0))
        self.view.addConstraint(NSLayoutConstraint(item: hostingController.view!, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1.0, constant: 0.0))
        self.view.addConstraint(NSLayoutConstraint(item: hostingController.view!, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.view, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1.0, constant: 0.0))
    
        hostingController.didMove(toParent: self)
        hostingController.view.invalidateIntrinsicContentSize()
    }
}

You can load the middle controller from UIKit as follows

navigationController?.pushViewController(WireHostingControllerVC(), animated: true)

Leave a Reply

Your email address will not be published.