Search code examples
iosuinavigationcontrolleruitabbarcontrollerseguepushviewcontroller

iOS Storyboard presenting tab bar modally vs push in XCode 8


Consider a storyboard where we have UITabBarController, in it any UIViewController(lets call it VC) embedded in a UINavigationController. We want VC to have a BarButtonItems on its navigation bar. This storyboard is presented by push segue from another storyboard (having another navigation controller).

Everything looks OK in XCode, but navigation bar does not change in VC at the runtime. However when I change presenting this storyboard from push to modal, everything seems to be fine. IMHO it is because of embedding the navigation controller but I do not see any reason why it is not working. Any idea how to fix it legally (presenting by push) and without any pain would be helpful.

Thanks in advance


Solution

  • So I think you will have to employ some code to fix your issue but not much. I built a test project to test this and will attach images along with code. First if I understand you correctly you have a navigationController push the new storyboard in question. See attached image.MainStoryboard

    I named the storyboard being pushed because that is what is happening. Then in my storyboard named Push here is the setup. Push.storyboard

    In the first view controller of the tabbarcontroller I added the below code. Obviously this hides the navigation controller that pushed us here. If you then visit controller number 2 our new navigation controller and items show. If hiding the navigation controller in the tabbarcontroller view controller 1 is not what you want to do then. continue reading.

     override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
       //or to unhide from returning the opposite ->self.parent?.navigationController?.isNavigationBarHidden = true
        self.parent?.navigationController?.isNavigationBarHidden = true
    }
    

    If you did not want to hide the navigation controller in the first view controller but when visiting controller 2 you want to see your items then add this to your viewWillAppear and in the first controller in viewWillAppear change the code from true to false.

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        // Do any additional setup after loading the view, typically from a nib.
        self.parent?.navigationController?.isNavigationBarHidden = true
    }
    

    This hides the parent navigation controller as basically that was covering up your navigation controller in your example. So above hides the parent navigation controller. This is also why presenting modally worked. Your navigation controller was hidden from the start. Hope this helps.

    **Edit If you want the navigation controller in tab 2 view controller but you want to keep the parent in tab one to be able to go back with the back button you can set this in viewWillAppear instead so it would look like this in view controller 1.

     //tabcontroller vc 1
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.navigationController?.isNavigationBarHidden = false
    }
    

    And in tabcontroller view controller 2 with the item in the bar you could do this. //tabbarcontroller vc 2 with own navigationcontroller override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) self.parent?.navigationController?.isNavigationBarHidden = true }

    Finally if you want the back button visible in both controllers but want different right buttons do it programmatically in viewWillAppear

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
             self.tabBarController?.navigationItem.setRightBarButton(UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(FirstViewController.editSomthing)), animated: true)
    }
    

    And if you want to remove it in the other controller

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        self.tabBarController?.navigationItem.rightBarButtonItem = nil;
    }
    

    In Both of the above examples directly above this, we are keeping the parent navigation controller so you would not need to embed your view controllers of the tab controller inside uinavigation controller.

    You could also use a combo of the above code if you want the hide/show parent navigation controller in viewWillAppear as well. Some of this is dependent on the view hierarchy you choose now and in the future.