iOS 11中如何单独设置导航栏BarButtonItem启用状态颜色
Hey there! I totally get your frustration with this iOS 11 quirk—let’s break down why this is happening and how to fix it.
Why Your Current Code Isn’t Working
In iOS 11, Apple changed how UIBarButtonItem handles tint colors under the hood. When you use UIButton.appearance(whenContainedInInstancesOf: [UINavigationBar.self]).tintColor = UIColor.red, you’re setting the base tint color for all buttons inside navigation bars. The problem is, iOS automatically adjusts this tint color for the disabled state (usually by lowering its opacity or desaturating it), so both enabled and disabled states end up tied to your red tint color.
Solution 1: Use a Custom UIButton for Precise Control
The most reliable way to separate enabled and disabled state colors is to create a custom UIButton and use it as the customView for your UIBarButtonItem. This lets you explicitly set colors for each state:
// Create your custom button let actionButton = UIButton(type: .system) actionButton.setTitle("Save", for: .normal) // Set enabled state color actionButton.setTitleColor(.red, for: .normal) // Optional: Set disabled state color (or let iOS use its default desaturated version) actionButton.setTitleColor(.systemGray, for: .disabled) // Add action and wrap in BarButtonItem actionButton.addTarget(self, action: #selector(handleButtonTap), for: .touchUpInside) let barButton = UIBarButtonItem(customView: actionButton) // Assign to navigation bar navigationItem.rightBarButtonItem = barButton
If your bar button uses an icon instead of text, you can set the image tint color per state too:
actionButton.setImage(UIImage(systemName: "checkmark")?.withTintColor(.red, renderingMode: .alwaysOriginal), for: .normal) actionButton.setImage(UIImage(systemName: "checkmark")?.withTintColor(.systemGray, renderingMode: .alwaysOriginal), for: .disabled)
Solution 2: Adjust Navigation Bar Tint (For Global Changes)
If you want all enabled bar buttons in your app to be red, and let iOS handle the disabled state automatically (it’ll desaturate the red to a muted gray), you can set the navigation bar’s tint color directly:
UINavigationBar.appearance().tintColor = .red
This way, enabled buttons are bright red, and disabled ones get the system’s default disabled treatment (without you having to define it manually).
Key Takeaway
iOS 11 shifted UIBarButtonItem to rely more on inherited tint colors rather than per-state text attributes for system-style buttons. For full control over enabled vs disabled colors, going with a custom UIButton as the bar button’s custom view is the way to go—it avoids the ambiguity of how iOS applies tint adjustments across states.
内容的提问来源于stack exchange,提问作者Bita

