Home > Software design >  How do you add a bar button item to all View Controllers in a Navigation Controller
How do you add a bar button item to all View Controllers in a Navigation Controller

Time:07-21

Within my scene delegate, I'm creating a navigation controller and attempting to add a right bar button item to all the view controllers. Here's my code within scene delegate

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
   
    guard let windowScene = (scene as? UIWindowScene) else { return }
 
    let window = UIWindow(windowScene: scene)

    let viewController = IntroViewController()
    let navigation = UINavigationController(rootViewController: viewController)
    
    navigation.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Test", style: .done, target: nil, action: nil)
    navigation.navigationItem.rightBarButtonItem?.tintColor = .red
    
    let standardAppearance = UINavigationBarAppearance()
    standardAppearance.backgroundColor = .black
    
    navigation.navigationBar.standardAppearance = standardAppearance
    navigation.navigationBar.scrollEdgeAppearance = standardAppearance
    

    window.rootViewController = navigation
    self.window = window
    window.makeKeyAndVisible()
}

Unfortunately, this code doesn't add any bar button item to the navigation controller on any of the view controllers.

However, when I add this line of code to one of my view controllers within viewDidLoad, it'll add the navigation bar button item to only that view controller.

self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Exit", style: .plain, target: self, action: #selector(exitPressed))

Is there a way to add a bar button item to all the view controllers within a navigation controller programmatically.

CodePudding user response:

There's a couple ways you could do it.


Make the SceneDelegate the delegate of the navigation controller then add the button to ever view controller shown.

func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
    viewController.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Exit", style: .plain, target: self, action: #selector(exitPressed))
}

Make a view controller subclass that just sets the right bar button item. Then each screen that needs the button can subclass it.

class ExitButtonViewController: UIViewController {
    init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Exit", style: .plain, target: self, action: #selector(exitPressed))
    }


    func exitPressed() {
        // add a common implementation or require the subclass to add one.
    }
}

Make a protocol that can simplify adding the button in multiple view controllers.

protocol Exitable: NSObjectProtocol {
    func exitPressed()
}

extension Exitable where Self: UIViewController {
    func setupExitButton() {
        navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Exit", style: .plain, target: self, action: #selector(exitPressed))
    }
}

class SomeViewController: UIViewController, Exitable {
    init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        setupExitButton()
    }

    func exitTapped() {
        // Do something
    }
}
  • Related