Hide/Show Navigation Bar at ViewWillAppear and ViewWillDisappear UI Glitch

Viewed 571

so I have 2 VC that I want to set its navigation bar hide when it appears and show again when it disappears. This is my code

class FirstNavigationVCViewController: UIViewController {

    @IBOutlet weak var button: UIButton!
    override func viewDidLoad() {
        super.viewDidLoad()

        title = "First Nav"
        button.addTarget(self, action: #selector(press), for: .touchUpInside)
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationController?.setNavigationBarHidden(true, animated: true)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        navigationController?.setNavigationBarHidden(false, animated: true)
    }
    
    
    @objc func press() {
        navigationController?.pushViewController(SecondNavigationViewController(), animated: true)
    }

}

class SecondNavigationViewController: UIViewController {

    @IBOutlet weak var button: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        title = "Second Nav"
        button.addTarget(self, action: #selector(press), for: .touchUpInside)
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationController?.setNavigationBarHidden(true, animated: true)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        navigationController?.setNavigationBarHidden(false, animated: true)
    }
    
    @objc func press() {
        navigationController?.popViewController(animated: true)
    }
}

I assume with that code the navigation bar will not show up when the second vc pop, but instead I got this

enter image description here

do you guys have better solution so I can still hide navigation bar for both vc without that animation?

3 Answers

If you want your navigation bar to be hidden then why in viewWillDisappear(_:) of both view controllers do you call navigationController?.setNavigationBarHidden(false, animated: true)?

What's happening is the moment the first view controller starts to disappear the navigation bar comes back and the moment the second view controller starts to appear it goes away again. This also happens in reverse.

If you want it to be there in the first view controller and not there in the second view controller, then on the first view controller's viewWillDisappear(_:) call

navigationController?.setNavigationBarHidden(true, animated: true)?

Just remove all animation from the navigationBar layer before making new animations.

class TestVC: UIViewController {
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        navigationController?.setNavigationBarHiddenSafe(true, animated: animated)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        navigationController?.setNavigationBarHiddenSafe(false, animated: animated)
    }
}

extension UINavigationController {
    func setNavigationBarHiddenSafe(_ hidden: Bool, animated: Bool) {
        navigationBar.layer.removeAllAnimations()
        setNavigationBarHidden(hidden, animated: animated)
    }
}

This is kind of dirty way - apple may change this behaviour in future and it'll stop working(which is unlikely, but still). Perfectly you'd need to use some router that'll resolve nav controller state and manage navigation var visibility.

During navigation set the animated value to false instead of true.

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    navigationController?.setNavigationBarHidden(true, animated: false)
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    navigationController?.setNavigationBarHidden(false, animated: false)
}
Related