0

I am using MVVM+C pattern to build my app. Currently I am facing a problem with changing the native back button title and image of navigation bar to the custom image without the title. I've tried a lots of solutions what I was able to find, but nothing set the different title or even an image. I've ended up with this code in AppDelegate.swift:

let navigationController: UINavigationController = .init()
    
    if #available(iOS 13.0, *) {
        let appearence = UINavigationBarAppearance()
        appearence.configureWithOpaqueBackground()
        appearence.backgroundColor = .backgroundColor
        appearence.shadowColor = nil
        appearence.shadowImage = nil
        
        navigationController.navigationBar.standardAppearance = appearence
        navigationController.navigationBar.scrollEdgeAppearance = navigationController.navigationBar.standardAppearance
    } else {
        navigationController.navigationBar.isTranslucent = false
        navigationController.navigationBar.barTintColor = .backgroundColor
        navigationController.navigationBar.shadowImage = nil
        navigationController.navigationBar.shadowColor = nil
    }
    // This code is not working at all, always get "Back" as a default with default image =====

    let backButtonBackgroundImage = UIImage(named: "backButton")
    navigationController.navigationBar.backIndicatorImage = backButtonBackgroundImage
    navigationController.navigationBar.backIndicatorTransitionMaskImage = backButtonBackgroundImage
    
    let backBarButtton = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
    navigationController.navigationItem.backBarButtonItem = backBarButtton
    
    // =========

    navigationController.navigationBar.tintColor = .primary
    
    window?.rootViewController = navigationController
    window?.makeKeyAndVisible()

Also, I've followed the official documentation but without any success. As default I've set the navigation bar as hidden (because is not needed for multiple times) and I am showing it in ViewWillAppear and hiding in ViewWillDisappear methods.

Is there someone who has an idea of what's going on? Thanks!

The result of this code: Back button

Expected result: Expected back button

This is what I get with the new code: enter image description here

SOLUTION: After using code from Scott I was able to change the image and look of the navigation bar but I lost the ability to swipe back. After adding this code to the UINavigationBar extension I was able to get it back:

extension UINavigationController: UIGestureRecognizerDelegate {
@objc func goBack(sender: Any?) {
    self.popViewController(animated: true)
}

override open func viewDidLoad() {
    super.viewDidLoad()
    interactivePopGestureRecognizer?.delegate = self
}

public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    return viewControllers.count > 1
}
}
Peter Hlavatík
  • 117
  • 1
  • 1
  • 11

1 Answers1

1

Below is some Playground code that shows a UINavigationController with a custom back button that is an image.

Note that what it does is hides the system provided back button, then substitutes another button that still performs the "back" action but on a custom UINavigationController.

There may be a more efficient way to duplicate the functionality of "back" that doesn't involve a custom class and a custom target-action setup, but I couldn't find one quickly so finding that solution can be left as an exercise for the reader.

import UIKit
import SwiftUI
import PlaygroundSupport

NSSetUncaughtExceptionHandler { error in
    debugPrint(error)
}

class MyNavController : UINavigationController {
    @objc func goBack(sender: Any?) {
        self.popViewController(animated: true)
    }
}

let navDestination1 = UIViewController()
navDestination1.navigationItem.title = "Destination 1"

let navigationController = MyNavController(rootViewController: navDestination1)

if #available(iOS 13.0, *) {
    let appearence = UINavigationBarAppearance()
    appearence.configureWithOpaqueBackground()
    appearence.backgroundColor = .purple
    appearence.shadowColor = nil
    appearence.shadowImage = nil

    navigationController.navigationBar.standardAppearance = appearence
    navigationController.navigationBar.scrollEdgeAppearance = navigationController.navigationBar.standardAppearance
} else {
    navigationController.navigationBar.isTranslucent = false
    navigationController.navigationBar.barTintColor =  .purple
    navigationController.navigationBar.shadowImage = nil
}

let navDestination2 = UITableViewController()
navDestination2.navigationItem.title = "Destination 2"
navDestination2.navigationItem.hidesBackButton = true
navDestination2.navigationItem.leftBarButtonItem = UIBarButtonItem(
    image: UIImage(systemName: "multiply.circle.fill"),
    style: UIBarButtonItem.Style.done,
    target: navigationController,
    action: #selector(MyNavController.goBack))


navigationController.pushViewController(navDestination2, animated: true)

navigationController.view.bounds = CGRect(x: 0,y: 0,width: 320,height: 480)

PlaygroundSupport.PlaygroundPage.current.liveView = navigationController
Scott Thompson
  • 22,629
  • 4
  • 32
  • 34
  • Hi Scott, for me in my project all the things remains the same. No change of the icon or title when I've used your code directly in ViewController or also in AppDelegate... I am still able to change only the tint color. – Peter Hlavatík Oct 13 '21 at 06:29
  • Does the sample I posted, run in a playground, show a custom back button on your setup? – Scott Thompson Oct 13 '21 at 13:20
  • Yeah, I'm able to run it in playground and all is set as desired... but when I put the same code on the same place in my project nothing happens. I am only able to change the colors... – Peter Hlavatík Oct 16 '21 at 18:07
  • Check the result from the project, it's different from playground – Peter Hlavatík Oct 18 '21 at 14:29
  • Realize that I didn't have your image and so my code is using one of the system images (the round button with an X in it) instead of whatever image you wanted to use. – Scott Thompson Oct 18 '21 at 16:30
  • Yep, replacing the image is not a problem, but I want to get rid of the "<" button, I want to replace that one ... – Peter Hlavatík Oct 19 '21 at 15:24
  • Yeah... I didn't pay close enough attention to my original implementation vs. the effect you wanted. I completely changed the solution above. See if it helps more to get what you want. – Scott Thompson Oct 19 '21 at 15:55
  • Thank you, the solution worked, but I've lost the swipe back option... is there any chance to get it back? – Peter Hlavatík Oct 19 '21 at 16:31
  • I might try attaching a custom swipe gesture recognizer to the view and having it trigger the 'goBack' action too? No telling what other default behavior might be missing though. Apple REALLY seems to want that back '<' to show. – Scott Thompson Oct 19 '21 at 16:38
  • So basically, when I want to have custom back button, I will lost the swipe gesture? :( there is no chance of getting it just replaced – Peter Hlavatík Oct 19 '21 at 17:02
  • I've updated the question with solution, thanks for help! – Peter Hlavatík Oct 20 '21 at 17:58