Dan
Dan

Reputation: 303

Changing the tint colour of elements in UINavigationbar (iOS 11)

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 UINavigationButtons, 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:

iOS 10 Vs. 11 UINavigationBar button 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

Answers (4)

Johannes Fahrenkrug
Johannes Fahrenkrug

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 UIButtons 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 UIBarButtonItems, including the back button, are white.

Upvotes: 1

schmru
schmru

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

Peter Lapisu
Peter Lapisu

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

dehlen
dehlen

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

Related Questions