17
votes

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!

2
Have you managed to find a solution? I built a UINavigationBar extension for settings a height value and using that value for computing the sizeThatFits frame. Now I can use this extension to update the height on viewWillAppear, by setting the navigationBar height inside an animation loop and calling navigationBar.sizeToFit(). Works great when pushing, unfortunately not so great when popping back. Tried reseting the frame in the same way on viewWillDissapear or on viewWillAppear for the previous controller.alexbumbu
Any progress, guys?Andrey Gagan
@user370773 You can check my edited answer. I changed the way that I animate navigationBar height. It works for swipe and pop button.kamwysoc

2 Answers

6
votes

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

  • Title jumps to top

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.

0
votes

I think now you can achieve something similar with just this, just set large title to always:

enter image description here