Search code examples
iosuinavigationcontrolleruinavigationitem

Use `navigationItem.backButtonDisplayMode = .minimal` with a custom back button image


For an iOS 14+ app I'd like to use navigationItem.backButtonDisplayMode = .minimal to hide the back button title, while still having the title available in the back button's long-press menu. Which works.. however I also want to change the back button image, to replace the default chevron.

But no matter what I try, I can't seem to find a solution that shows a custom back button image without a title, while also not showing a blank space in the back button's long-press menu, and not breaking the slide-to-go-back-gesture.

Anyone tried something similar, and succeeded?

So in the first view controller I show a title:

enter image description here

And then in the pushed view controller I want to show a custom back button image WITHOUT the "one" title (as seen below), and still have the long-press menu say "one" instead of a blank space.

enter image description here

This mostly gets me there actually, except that it breaks the gesture to slide to go back:

override func viewDidLoad() {
  super.viewDidLoad()

  let backImage = UIImage(named: "backImage")?.withRenderingMode(.alwaysOriginal)
  navigationController?.navigationBar.backIndicatorImage = backImage
  navigationController?.navigationBar.backIndicatorTransitionMaskImage = backImage

  navigationItem.backButtonDisplayMode = .minimal
}

Update: actually it only seems to break on the simulator, it's all fine on an actual device. I now have a minimal project setup where it all works, now to find out why it doesn't work in my actual big project!


Solution

  • Okay, I finally figured out all the problems I was having.

    Basically, this code works just fine:

    override func viewDidLoad() {
      super.viewDidLoad()
    
      let backImage = UIImage(named: "backImage")?.withRenderingMode(.alwaysOriginal)
      navigationController?.navigationBar.backIndicatorImage = backImage
      navigationController?.navigationBar.backIndicatorTransitionMaskImage = backImage
    
      navigationItem.backButtonDisplayMode = .minimal
    }
    

    But I was having problems with the swipe back gesture not working anymore. Turns out, that's a simulator bug, works fine on device. Then there was the problems that the custom back button image didn't actually show up in my view, because of this:

    let appearance = UINavigationBarAppearance()
    appearance.backgroundColor = .pageBackground
    appearance.titleTextAttributes = [.foregroundColor: UIColor.abbey]
    appearance.shadowColor = .clear
    
    navigationBar.scrollEdgeAppearance = appearance
    navigationBar.standardAppearance = appearance
    navigationBar.compactAppearance = appearance
    

    As soon as you set a custom appearance, that completely wipes away the custom back button image. Simple fix, just set these things directly on the navigationBar without involving the appearance.

    And now it all works!