loading...

iOS: How to properly customize system controls like UINavigationBar, UITabBar and more

nemecek_f profile image Filip Němeček ・2 min read

In this blog post let’s look how to customize standard iOS UIKit controls in an easy way that will ensure your app looks consistent. Let’s use an UINavigationBar as an example. This is pretty common because the standard blue tint just does not look good.

Of course there are many many ways how to customize this control. You can select it in Interface Builder and with Attributes inspector set the properties like background color, tint color and more to your liking.

However this has one BIG drawback. You need to remember to change all navigations bar and make sure to select same properties otherwise your app won’t have consistent look. This same problem happens when you modify the control inside viewDidLoad method.

Another possible way would be to create custom subclass and in its init change the properties to your liking. This is better but you once again have to bear in mind that you have to use this subclass in all places where you have UINavigationBar.

So those solutions aren’t ideal, let’s look how this kind of customization is done properly thanks to an API that Apple introduced in iOS 5. It is called appearance proxy and we can access it by calling method appearance on UIKit classes.

How it works? 🤔 Basically we get back “pseudo” instance that has the same properties as instances of current component but changes are then “forwarded” to all instances of this control.

There is one important caveat and that is that those changes will not apply to controls already in a view hierarchy meaning those already on the screen. If you want to apply changes to those you need to remove them from the hierarchy and add them again.

That is why those appearance proxies should be configured when the app launches. For once AppDelegate is perfect place to do this.

appearance() usage

Let’s see how to use appearance to customize some controls.

UINavigationBar.appearance().tintColor = Theme.Colors.primary
UITextField.appearance().tintColor = Theme.Colors.primary

This is an example from one of my recent projects. The tint color of the UITextField will affect the color of the cursor and text selection indicator.

I also think it is a good idea to have your app colors in one place. Even if you are using something like systemBlue or any other built-in color. Having it in one place means you can easily experiment with other colors.

If you want to customize multiple properties of one control, you can just grab the reference to the appearance proxy and use that.

let navigationBar = UINavigationBar.appearance()
navigationBar.tintColor = Theme.Colors.primary
navigationBar.prefersLargeTitles = true
navigationBar.backgroundColor = Theme.Colors.complementary

Then don’t forget to call these customizations here:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool

And you are good to go! 👍

Posted on Apr 26 by:

nemecek_f profile

Filip Němeček

@nemecek_f

Primarily iOS developer, I also like Django and Python. And dabble with JavaScript occasionally. Love reading and coffee.

Discussion

markdown guide