Search code examples
iosswiftxcodeuinavigationcontroller

Navigation bar not displaying inside childViewController


I have created a hamburger menu in my ios app.

I have a navigationBar in my rootViewController but now I need to move the navigationBar to one of my childViewController for some of the functions/buttons to work.

Now that I have moved it into a childViewController the navigationBar doesn't display. If I make the childViewController the rootController the navigationBar displays fine, this is because in my appDelegate I have the rootController as a navigationController.

It is only when I make it a childViewController that the navigationBar decides to not display. Not sure what I need to do for it to work.

Here is my appDelegate where I am making the rootViewController:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        window = UIWindow(frame: UIScreen.main.bounds)
        window?.makeKeyAndVisible()
        window?.rootViewController = UINavigationController(rootViewController: jobListController())


        return true
    }

This is my hamburger menu's viewDidLoad (rootViewController) where I am adding the childViewControllers:

override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor.white

        // ADD VIEWCONTROLLERS TO MENU
        view.addSubview(sideBarUIView)

        addChildViewController(sideBar)
        view.addSubview(sideBar.view)
        sideBar.view.center = sideBarUIView.center

        addChildViewController(jobList)
        view.addSubview(jobList.view)
        jobList.view.center = overlayView.center

        // ADD UI VIEWS TO HAMBURGER MENU
        view.addSubview(overlayView)
        overlayView.isHidden = true
    }

This is the childViewController that I want to add the navigationBar to:

class jobListController: UIViewController {
        super.viewDidLoad()

        navigationController?.navigationBar.barTintColor = UIColor(red:1.00, green:1.00, blue:1.00, alpha:1.0)
        navigationController?.view.backgroundColor = UIColor(red:1.00, green:1.00, blue:1.00, alpha:1.0)
        navigationController?.navigationBar.shadowImage = UIImage()

        navigationItem.title = "JOBS"

        let searchButton = UIBarButtonItem(barButtonSystemItem: .search, target: self, action: #selector(HandleSearch))
        let addNewJobButton = UIBarButtonItem(barButtonSystemItem: .compose, target: self, action: #selector(HandleNewJob))
        searchButton.tintColor = UIColor(red:0.63, green:0.63, blue:0.63, alpha:1.0)
        addNewJobButton.tintColor = UIColor(red:0.63, green:0.63, blue:0.63, alpha:1.0)

        navigationItem.rightBarButtonItems = [addNewJobButton, searchButton]
    }
}  

Edit:

After using Lukáš Mareda's answer which seemed to fix the problem I was having, it created a new problem.

On my rootController (hamburger menu) I can slide right anywhere on the screen and it will open the hamburger menu, this is great as this is the desired effect.

One of my child viewControllers that is inside my hamburgerMenu has a tableView. If I click on one of the cells and go to a new viewController the hamburger menu can still be accessed by sliding right.

I only want to be able to access the hamburger menu at the top level but it seems taht I can access it anywhere on my app now.


Solution

  • 1) Hamburger Menu view controller should be subclass of UIViewController. And first step in appDelegate:

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    
            window = UIWindow(frame: UIScreen.main.bounds)
            window?.rootViewController = HamburgerViewController()
            window?.makeKeyAndVisible()
    
            return true
        }
    

    2) HamburgerView controller should embed NavigationController (or its subclass) with some rootview controller. So in HamburgerViewController

    override func viewDidLoad() {
            super.viewDidLoad()
    
            view.backgroundColor = UIColor.white
    
            // ADD VIEWCONTROLLERS TO MENU
            view.addSubview(sideBarUIView)
    
            addChildViewController(sideBar)
            view.addSubview(sideBar.view)
            sideBar.view.center = sideBarUIView.center
    
            let navigationController = UINavigationController(rootViewController: jobListController())
            addChildViewController(navigationController)
            view.addSubview(navigationController.view)
            navigationController.view.center = overlayView.center
    
            // ADD UI VIEWS TO HAMBURGER MENU
            view.addSubview(overlayView)
            overlayView.isHidden = true
        }
    

    3) JobList can stay at it is. I assume that in current state, the navigationController property was nil

    Updated answer

    There is two ideas about handling your hamburgerGestureRecognizer

    1) You can add the hamburgerGestureRecognizer into rootViewController.view in your case it was JobList so the gesture recognizer will be only in rootViewController

                let jobList = jobListController()
                let navigationController = UINavigationController(rootViewController: jobList)
                addChildViewController(navigationController)
                view.addSubview(navigationController.view)
                joblist.view.addGestureRecognizer(hamburgerGestureRecognizer)
                navigationController.view.center = overlayView.center
    

    And at place where you switching between screens in hamburgerMenu you can reuse this recognizer

    viewControllerToPresent.view.addGestureRecognizer(hamburgerGestureRecognizer)
    

    2) You can implement the gesture recognizer's delegate function and conditionally disable it according presenting viewController. Something like this:

        func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
            return currentlyPresentedNavigationController.viewControllers.count == 1
        }