切换ViewController时如何动态添加/隐藏UIBarButtonItem?
Absolutely feasible! This is a super common scenario for customizing navigation bars in iOS, and there are a couple of clean, reliable ways to implement this—whether you want to handle it directly in your target ViewController or via the navigation controller's delegate.
Option 1: Use ViewController Lifecycle Methods
This is the most straightforward approach if you only need this behavior for a single ViewController. We'll leverage viewWillAppear (to add the button when the screen is about to show) and viewWillDisappear (to remove it when leaving the screen).
Step 1: Declare a Property for the Dynamic Button
First, add a stored property to your ViewController to keep track of the button we'll create dynamically (this prevents us from re-creating it every time the screen appears):
private var filterBtn: UIBarButtonItem?
Step 2: Add the Button When the View Appears
In viewWillAppear, we'll grab the existing bar button items from Storyboard, append our new button, and update the navigation item:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // Create the button only once if filterBtn == nil { filterBtn = UIBarButtonItem(title: "Filter", style: .plain, target: self, action: #selector(filterAction(sender:))) } // Get existing buttons (fallback to empty array if none exist) var existingButtons = navigationItem.rightBarButtonItems ?? [] // Add our dynamic button to the array existingButtons.append(filterBtn!) // Assign back to update the navigation bar navigationItem.rightBarButtonItems = existingButtons }
Step 3: Remove the Button When the View Disappears
In viewWillDisappear, we'll filter out our dynamic button from the existing array:
override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // Remove only our dynamic button, keep the Storyboard ones intact navigationItem.rightBarButtonItems = navigationItem.rightBarButtonItems?.filter { $0 !== filterBtn } }
Step 4: Add the Button Action
Don't forget to implement the selector for your button's tap event:
@objc private func filterAction(sender: UIBarButtonItem) { // Add your button logic here print("Filter button tapped!") }
Option 2: Use UINavigationController Delegate
If you need this behavior across multiple ViewControllers or want a more centralized approach, use the navigation controller's delegate methods.
Step 1: Set Up the Delegate
In your ViewController's viewDidLoad, set itself as the navigation controller's delegate:
override func viewDidLoad() { super.viewDidLoad() navigationController?.delegate = self }
Step 2: Implement the Delegate Method
Add an extension to conform to UINavigationControllerDelegate and handle the navigation transition:
extension YourViewController: UINavigationControllerDelegate { func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) { if viewController === self { // Add the dynamic button (same creation logic as Option 1) if filterBtn == nil { filterBtn = UIBarButtonItem(title: "Filter", style: .plain, target: self, action: #selector(filterAction(sender:))) } var existingButtons = navigationItem.rightBarButtonItems ?? [] existingButtons.append(filterBtn!) navigationItem.rightBarButtonItems = existingButtons } else { // Remove the dynamic button when navigating away navigationItem.rightBarButtonItems = navigationItem.rightBarButtonItems?.filter { $0 !== filterBtn } } } }
Key Notes
- Avoid Duplicate Buttons: By storing the button as a property and only creating it once, we prevent adding multiple instances of the filter button every time the ViewController appears.
- Preserve Storyboard Buttons: Using
rightBarButtonItems(the array version) instead ofrightBarButtonItemensures we keep the two buttons you added in Storyboard while adding the third dynamically. - TabBar Compatibility: Both methods work seamlessly if your ViewController is part of a UITabBarController, since
viewWillAppearand the navigation delegate methods will still trigger when switching tabs.
内容的提问来源于stack exchange,提问作者user11733397

