Search code examples
iosswiftuinavigationcontrollerchildviewcontroller

Adding UINavigationController as child of other UINavigationController


I'm experimenting with adding a UINavigationController as a child of another UINavigationController. The problem I'm facing is that the navigation bar of the child UINavigationController doesn't respect the safe area at the top - the height is too small and the navigation bar is covered by the notch.

In the screenshot below, the yellow navbar and view is part of the child UINavigationController, while the blue view, and white navigation bar, is part of the root UINavigationController. The child UINavigationController is supposed to only cover part of the screen. If everything worked as intended, the yellow Navigation bar should have the same size as the white navigation bar.

enter image description here

One might think that it's not a good idea to add child view controllers to a UINavigationController, but I'm developing a component that can be used to display a "sidebar" navigation or drawer and it can potentially be added as a child to any view controller, of any type.

Here's some code that reproduces the problem I'm having:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    
    self.view.backgroundColor = .blue
    self.title = "Parent"
    
    let childVC = UIViewController()
    childVC.view.backgroundColor = .yellow
    childVC.title = "Modal"
    
    let childNavController = UINavigationController(rootViewController: childVC)
    childNavController.view.translatesAutoresizingMaskIntoConstraints = false
    
    let rootNavController = self.navigationController!
    
    rootNavController.addChild(childNavController)
    rootNavController.view.addSubview(childNavController.view)
    
    NSLayoutConstraint.activate([
        childNavController.view.widthAnchor.constraint(equalToConstant: 300),
        childNavController.view.topAnchor.constraint(equalTo: rootNavController.view.topAnchor),
        childNavController.view.bottomAnchor.constraint(equalTo: rootNavController.view.bottomAnchor),
        childNavController.view.rightAnchor.constraint(equalTo: rootNavController.view.rightAnchor)
    ])
    childNavController.didMove(toParent: rootNavController)
}

Solution

  • Proper approach is be to make a common parent for both UINavigationControllers - just empty UIViewController and then embedded both of those as child viewcontrollers using containment.

    UINavigationController has a build in management for subviews, when you use it (show/hide viewcontrollers) and it's risky to embed child views and child viewcontrollers to it like that.