iOS Color War! Appearance Proxy vs UIButton Title Text Color

Now here’s a weird issue that appeared in iOS 10, I found myself saying one day. I was seeing an iOS button’s title change color as a I navigated from one scene to the next. It got worse. When I navigated back, the button’s title color stayed the wrong color. It was the same color as all the labels in the iOS app. What’s going on?

We dug in deeper and discovered something. There was a nasty appearance proxy color issue where the appearance proxy would change the color of the UIButton‘s title text color even though the code was explicitly setting the color. In fact, the appearance proxy would set it to be the same color as it has configured for all UILabel objects. The configuration code for labels was like this:

UILabel.appearance().textColor = labelTextColor()

Since a UIButton contains a UILabel, that might make sense. How does one fix this situation?

The answer to fixing it was discovered after thinking about what was read in this Stack Overflow post titled Appearance Proxy overridden when resetting text:

iOS applies appearance changes when a view enters a window, it doesn’t change the appearance of a view that’s already in a window.

It turns out the code to explicitly set the color on the UIButton was getting called before the view appeared on the screen aka viewWillAppear. Once the view appeared on the screen, the appearance proxy would set the button’s label’s text color aka button title color.

As a side note, this only seemed to happen when using setAttributedTitle on the button as opposed to calling setTitleColor and setTitle separately. Unfortunately, we wanted different parts of the text to be different sizes. So, using setAttributedTitle still seemed like the thing we should do.

Given all that knowledge, we called setNeedsLayout on the UIButton in viewWillAppear and viewWillDisappear That fixed everything up! The button no longer appeared to change color when switching between screens. Hurrah!

 

 

Leave a Reply

Your email address will not be published.