DEV Community

Fernando Martín Ortiz
Fernando Martín Ortiz

Posted on

5 3

Forgotten UIKit gems: UIAppearance

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:

Simulator Screen Shot - iPhone 11 - 2021-03-27 at 15.20.54

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
}
Enter fullscreen mode Exit fullscreen mode

Simulator Screen Shot - iPhone 11 - 2021-03-27 at 15.28.40

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
Enter fullscreen mode Exit fullscreen mode

Simulator Screen Shot - iPhone 11 - 2021-03-27 at 15.46.39

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)
Enter fullscreen mode Exit fullscreen mode

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.

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

Sentry mobile image

Improving mobile performance, from slow screens to app start time

Based on our experience working with thousands of mobile developer teams, we developed a mobile monitoring maturity curve.

Read more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay