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
}
}