Reputation: 303
I have been using this code to change the tint color of element in the navigation bar:
UINavigationBar.appearance().tintColor = theme.labelColor
However, this is no longer working in iOS 11. Before iOS 11, buttons in the Navigation Bar were UINavigationButton
s, but in iOS 11 they've been changed to _UIModernBarButton
. I was able to change their tint color with UIButton.appearance().tintcolor
, but that changes every button's.
Here's a comparison:
Anyone has any idea how to change the button tint color in the navigation bar?
UPDATE 01/09/2017:
Looks like _UIButtonBarButton
has the correct tint color, but _UIModernBarButton
overwrites it with the color set for UIButton
.
UPDATE 18/09/2017:
"Engineering has provided the following feedback regarding this issue:
UIView.tintColor is not an appearance selector, and specifically is documented as not working correctly as an appearance property due to its inheritance properties."
Upvotes: 19
Views: 5028
Reputation: 44700
Thank you very much for all these great answers. For me, this did the trick:
[[UIButton appearance] setTintColor:someDefaultColorForAllButtons];
/**
* Starting with iOS 11, UIBarButtonItems actually have a UIButton subview.
* That means that the [UIButton appearance]'s tintColor will override whatever
* tintColor would normally be set or passed-through to the barButtonItem (usually
* the UINavigationBar's tintColor). That's why we un-set the tintColor for
* UIButton when it's contained in an instance of UINavigationBar.
*/
[[UIButton appearanceWhenContainedIn:UINavigationBar.class, nil] setTintColor:nil];
We have a custom color for all our UIButton
s in the app (using [[UIButton appearance] setTintColor:]
. By doing that, we could never change the tintColor
of any UIBarButtonItem
(including the back button) on iOS 11. I had tried to set the tintColor
on a UINavigationBar
until I was blue in the face: All to no avail. Then I found this SO question and it finally pointed me in the right direction (thank you!).
The trick is this: Set the UIButton
's tintColor
to nil
when it's contained in a UINavigationBar
. That way, the UINavigationBar
's tintColor will be passed through to the UIBarButtonItem
and everything will work as expected.
Now, in my viewWillAppear:
method I can simply do this:
self.navigationController.navigationBar.tintColor = [UIColor whiteColor];
and all my UIBarButtonItem
s, including the back button, are white.
Upvotes: 1
Reputation: 619
I had the same problem with back button in navigation bar not being the colour I set for UINavigationBar with:
[[UINavigationBar appearance] setBackgroundColor:COLOR_NAVIGATION_BG];
[[UINavigationBar appearance] setBarTintColor:COLOR_NAVIGATION_BG];
[[UINavigationBar appearance] setTintColor:COLOR_NAVIGATION_FOREG];
Finally I got to the solution with:
[[UIButton appearanceWhenContainedIn:[UINavigationBar class], nil] setTintColor:COLOR_NAVIGATION_FOREG];
This line set the colour of navigation button.
I would also add that if you change the font of navigation button you need to add line to change the colour of text:
[[UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], nil] setTitleTextAttributes: @{NSFontAttributeName:FONT_MAIN_NAVIGATION} forState:UIControlStateNormal];
[[UIBarButtonItem appearanceWhenContainedIn:[UINavigationBar class], nil] setTitleTextAttributes: @{NSForegroundColorAttributeName:COLOR_NAVIGATION_FOREG} forState:UIControlStateNormal];
Upvotes: 0
Reputation: 20965
You could do
[[NSClassFromString(@"_UIModernBarButton") appearance] setTintColor:[UIColor redColor]];
this works, but you are tingling with a private class (this won't however get you rejected)
also you can have your own UINavigationController subclass and use it only where you need to
[[UIButton appearanceWhenContainedInInstancesOfClasses:@[MyNavigationController.class]] setTintColor:[UIColor redColor]];
Upvotes: 0
Reputation: 7389
So I did find kind of a solution. I am setting the tint color via the appearance proxy for UIButton but only when contained in an UINavigationBar. This looks like it is working for me. However still hoping that this behaviour will change in the iOS 11 GM or someone can come up with a better solution. Here is my working code:
if([UIButton respondsToSelector:@selector(appearanceWhenContainedInInstancesOfClasses:)]) {
[[UIButton appearanceWhenContainedInInstancesOfClasses:@[UINavigationBar.class]]setTintColor:navTintColor];
}
Swift version of appearance proxy call:
UIButton.appearance(whenContainedInInstancesOf: [UINavigationBar.self]).tintColor = UIColor.red
Upvotes: 16