17

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!

qfwfq
  • 976
  • 11
  • 30
  • 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 Dec 09 '16 at 16:41
  • Any progress, guys? – Andrey Gagan Mar 10 '17 at 16:28
  • @user370773 You can check my edited answer. I changed the way that I animate navigationBar height. It works for swipe and pop button. – kamwysoc Jul 20 '17 at 11:32

2 Answers2

7

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.

John
  • 540
  • 2
  • 15
kamwysoc
  • 6,709
  • 2
  • 34
  • 48
  • Thanks for the answer! It looks quite a good approach! The only problem though is that the `titleLabel` and `backButtonTitleLabel` jump to top as soon as the transition begins. I guess you need to apply some offset to them as well. – E-Riddie Jul 14 '17 at 11:52
  • Yeah, you're right the title offset is kind of a problem too. I'll try to fix that also. I'll update my answer if I get something new in my solution. :) – kamwysoc Jul 14 '17 at 11:54
  • I used to override `layoutSubviews` of my navigation bar when i customize navigationbar's height. just move all subview upper. – Codus Jul 14 '17 at 12:14
  • 1
    it seems that this answer is no longer working on iOS 11+ – Zimes Aug 28 '18 at 15:17
0

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

enter image description here

Markicevic
  • 1,025
  • 9
  • 20