Doug Smith
Doug Smith

Reputation: 29326

How to prevent using UIAppearance with UIView's tintColor from changing all UITabBar icon colours?

If I perform UIView.appearance().tintColor = ... the tintColor of all the icons in the tab bar change from the normal inactive grey state to whatever I set the tint color to.

I don't understand why this is the case. I'm just changing the tint color of the app, and by default the tint color doesn't mess with making all the tab bar icons look active at once.

How do I stop it from doing this? I want the tint color to change, but the unselected tabs to retain an inactive color.

Upvotes: 0

Views: 1002

Answers (2)

AverageHelper
AverageHelper

Reputation: 2221

I hope you've found a solution by now, but here's my two cents anyway.

Interface Builder doesn't use the UIAppearance API anywhere (as far as I am aware). It does, however, set properties on certain objects, to be applied to them as they're instantiated.

There is a "Global Tint" property in the File Inspector which controls the top-level default tintColor. It is worth noting that, unless explicitly told a different color to use (whether via UIView.appearance() or just UIView.tintColor) child views inherit their tintColor from their parent views. Remember, this chain continues up through the view hierarchy until it hits something that has a tintColor. Usually, it's the UIWindow it ends up hitting, and that has the default blue color of which Apple is so fond. Any dimming or temporary recoloring for state is inherited either from the view itself, or a close ancestor. This is important to note.

It is also good to note that you can respond to this in UIViewController by overriding the tintColorChanged() method, which gets called whenever this happens. By messing with UIView.appearance(), you effectively disable the chain of inheritance for every view in the hierarchy, and you let each fend for itself for its own colors. In my mind, there are at least two ways that this might prevent a UITabBar from properly representing a tab's state:

First, the tab bar has tinted image views under the hood, which inherit their tint color from the parent UITabBar. Even if they could get state-specific colors from the tab bar, the poor thing wouldn't have anything different to tell them, other than, "You were given a color, and you will respect that color!", followed by a slap and a sound flogging, at which point they would sulk back, knowing no more than before. By disabling the hierarchical tintColor inheritance system, you disable state. That's not good. Don't do that.

Second, by setting the tint color for every UIView regardless of state, you have told the tab bar items to hold that color regardless of state. That's not good. Don't do that either.

If you're using Interface Builder (or Storyboards if you prefer), I'd recommend setting that global tint color in the File Inspector, and leaving it at that. This would still set your tint color the way you want, while saving these poor views from domestic abuse.

If you need screenshots of where to find the File Inspector or the Global Tint option, I'd suggest poking around that sidebar on the right in Xcode. A little poking around never hurt anybody (except in movies).

Upvotes: 2

Nick
Nick

Reputation: 2369

What do you mean when you say you're "changing the tint color of the app"?

The UIView appearance proxy is doing exactly what you told it to. You asked it to set the tintColor of ALL UIViews in your app, which includes those views inside your UITabBar.

It sounds like you don't actually want to alter the tintColor of all UIViews, but instead want to target a specific subset. You should look into appearanceForTraitCollection or the (now deprecated) appearanceWhenContainedIn methods.

Upvotes: 0

Related Questions