iosiphoneuinavigationbarios10imessage

Messages-like taller / standard navigation bar during push / pop


iOS 10 Messages app's navigation bar increases/decreases the height when you push/pop a conversation (with a smooth transition).

Typically I make a taller custom navigation bar using sizeThatFits:, but it persists across pushes and pops of view controllers in a navigation controller.

How is it possible to have a taller navigation bar just for some view controllers across navigation sequences like the Messages app? Thanks!


Solution

  • Very interesting problem. I spent some time to achieve something like this in the Messages app and that is what I've done.

    enter image description here

    Finally, I use this trick to animate navigationBar height during push/pop and also pop with swipe gesture.

    UIView.beginAnimations(nil, context: nil)
    self.frame = navFrame
    UIView.commitAnimations()
    

    Below you can see my implementation:

    extension UINavigationBar {
        func applyHeight(_ height: CGFloat, animated: Bool = true) {
            var navFrame = self.frame
            navFrame.size.height = height
            if animated {
                UIView.beginAnimations(nil, context: nil)
                self.frame = navFrame
                UIView.commitAnimations()
            } else {
                self.frame = navFrame
            }
        }
    }
    
    class ViewControllerA: UIViewController {
    
        override func loadView() {
            super.loadView()
            title = "A"
            view.backgroundColor = .blue
            navigationItem.rightBarButtonItem = UIBarButtonItem(title: "NEXT", style: .plain, target: self, action: #selector(self.showController))
            navigationController?.navigationBar.isTranslucent = false
        }
    
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
        }
    
        func showController() {
            navigationController?.pushViewController(ViewControllerB(), animated: true)
        }
    }
    
    class ViewControllerB: UIViewController {
    
        override func loadView() {
            super.loadView()
            title = "B"
            view.backgroundColor = .red
        }
    
        override func viewWillAppear(_ animated: Bool) {
            navigationController?.navigationBar.applyHeight(100)
            super.viewWillAppear(animated)
        }
    
        override func willMove(toParentViewController parent: UIViewController?) {
            if parent == nil { // here you know that back button was tapped
                navigationController?.navigationBar.applyHeight(44)
            }
            super.willMove(toParentViewController: parent)
        }
    }
    

    Things to improve

    Jumping title is visible while you swipe to pop, but personally, I think this is a small problem :)

    Hope it helps you, and maybe someone can improve this implementation. Of course, I will still try to figure out how to make this better :) Here it's a github repository. Please use navigation_bar_height branch.