Fernando Martín Ortiz
Posted on March 27, 2021
What is UIAppearance
?
According to Apple docs, UIAppearance
is "A collection of methods that gives you access to the appearance proxy for a class.".
In simple words, you can modify the UIAppearance
object that is related to a certain view, and all of the views of that type will be affected. As simple and powerful (and dangerous) as that.
There is another possibility. You can specify that only the views contained in a parent view of type T will be affected by the appearance change.
Important note: the UIAppearance
customization needs to be performed before the views have entered in the UIWindow
. Otherwise, they won't be affected.
A practical example
Let's suppose we have this UI:
We can change the properties of all the UILabel
objects in that UI by changing their UIAppearance
. Let's put this in the AppDelegate
application(_:didFinishLaunchingWithOptions:)
method:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
UILabel.appearance().textColor = UIColor.systemGreen
return true
}
You can see how simple it is to update the properties in a view using UIAppearance
.
You may be wondering why the UILabel
inside UIButton
haven't been affected. The reason is that those labels are of type UIButtonLabel
.
In the case we don't want the UILabel
inside UITextField
to be affected by the changes in the UILabel
appearance, we can't do this:
UILabel.appearance(whenContainedInInstancesOf: [UITextField.self]).textColor = UIColor.lightGray
How it saved my life this week
To be honest, I've completely forgotten of UIAppearance
until this week it saved my project.
I had a WKWebView
where some scroll view indicators were randomly appearing in the middle of the screen.
I wasn't the only one experiencing this problems, as it was also happening in projects like React Native and Flutter.
Not only that. When I tried to debug the view hierarchy in my WKWebView
, I found that it was creating other UIScrollView
subclasses inside of it. And webView.scrollView
only affected the topmost scroll view.
I tried everything I found in the Github issues I've seen, but nothing worked. Then I remembered UIAppearance
, and did something like this:
UIScrollView
.appearance(whenContainedInInstancesOf: [MyWebView.self])
.scrollIndicatorInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 1)
Adding that immediately fixed all the scroll view inside the web view.
Caveats
While powerful, applying UIAppearance
everywhere is a VERY DANGEROUS anti-pattern you should be aware of. It's an extremely powerful tool when it's required, but shouldn't be used more than that.
Posted on March 27, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.