如何全局自定义APP中所有UINavigationBar返回按钮外观?
Hey there! Let’s fix that back button issue you’re facing. First, let’s clear up why your initial approach didn’t work—then I’ll show you a reliable, global solution that keeps all native return functionality intact.
Why Your Previous Attempt Failed
The backBarButtonItem property belongs to the previous view controller in the navigation stack, not the navigation controller itself. Setting it directly on your custom UINavigationController doesn’t target the right object, which is why your title change didn’t take effect.
The Global Fix (No Custom Selectors Needed)
The trick is to automatically configure the back button for every view controller as it gets pushed onto the stack. We’ll do this in your custom UINavigationController subclass, so you don’t have to repeat code in every VC.
Here’s the code:
class CustomNavigationController: UINavigationController { override func viewDidLoad() { super.viewDidLoad() // Remove the back arrow globally for this navigation controller navigationBar.backIndicatorImage = UIImage() navigationBar.backIndicatorTransitionMaskImage = UIImage() } override func pushViewController(_ viewController: UIViewController, animated: Bool) { // Only configure the back button if we're not pushing the first VC if viewControllers.count > 0 { // Create a back button with "Back" title—target/action nil lets iOS handle native return logic let backButton = UIBarButtonItem(title: "Back", style: .plain, target: nil, action: nil) // Assign this button to the current top VC's backBarButtonItem topViewController?.navigationItem.backBarButtonItem = backButton } super.pushViewController(viewController, animated: animated) } }
How This Works
- Arrow Removal: Setting
backIndicatorImageandbackIndicatorTransitionMaskImageto emptyUIImage()removes the arrow completely. - Global Title: Every time you push a new VC, we set the previous VC’s
backBarButtonItemto our custom "Back" button. Since we leavetargetandactionasnil, iOS automatically wires up the native pop functionality—no need to write your own selectors! - Non-Intrusive: If you ever need a custom back button for a specific VC, just set that VC’s
navigationItem.backBarButtonItemdirectly—it will override this global setting.
Alternative: UIAppearance for Even Wider Coverage
If you want to apply this to all navigation controllers in your app without subclassing, you can use UIAppearance in your app’s launch code (e.g., AppDelegate or SceneDelegate):
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Remove back arrow globally UINavigationBar.appearance().backIndicatorImage = UIImage() UINavigationBar.appearance().backIndicatorTransitionMaskImage = UIImage() // Hide the default title (shift it off-screen) and set our custom "Back" style let backButtonAppearance = UIBarButtonItem.appearance(whenContainedInInstancesOf: [UINavigationController.self]) backButtonAppearance.setBackButtonTitlePositionAdjustment(UIOffset(horizontal: -1000, vertical: 0), for: .default) backButtonAppearance.setTitleTextAttributes([ NSAttributedString.Key.foregroundColor: UIColor.systemBlue, // Match your app's color NSAttributedString.Key.font: UIFont.systemFont(ofSize: 17) ], for: .normal) return true }
Note: The UIAppearance approach has a small caveat—since UINavigationItem doesn’t support UIAppearance, we hide the default title by shifting it off-screen. The subclass method is more straightforward and reliable for most cases.
Final Checks
- Make sure all your navigation controllers in Storyboards or code use your
CustomNavigationControllersubclass. - Test pushing VCs—you should see "Back" with no arrow, and tapping it should pop the VC like normal.
内容的提问来源于stack exchange,提问作者smeshko

