/swift

Curious UIKit: Setting a custom UITabBar instance on UITabBarController

UIKit is a mature UI framework that provides a reasonable level of customizability, through its myriad styling properties and a multitude of delegate protocols declared on a whole variety of built-in classes and components. Every so often, however, I’ll come across what should be a trivial UI customization but isn’t.

Customizing UITabBarController with your own UITabBar object is one of those unexpected instances. Couldn’t we simply set UITabBarController’s tabBar property and be done with it?

@available(iOS 3.0, *)
open var tabBar: UITabBar { get }

Let’s take a gander at the docs before we do

You should never attempt to manipulate the UITabBar object itself stored in this property. If you attempt to do so, the tab bar view throws an exception.

Apple is threatening to unleash the big old runtime crash 💥 if you dare set the tabBar property yourself, so let’s not go there. And if you dig around a bit more, you’ll find, just like I did, that there just is no officially sanctioned way to provide UITabBarController with a custom UITabBar instance... It's an open property, but you're not allowed to provide your overriden implementation of it. [Insert sad_trombone.wav here]

Curiously, we can turn to Key-Value Coding, an Objective-C-based paradigm from the Cocoa framework which remains usable from Swift to this day. Instead of overriding or setting the tabBar property directly, we can set it using KVO’s setValue(_:forKey:) method, and call it from viewDidLoad.

override func viewDidLoad() {
  super.viewDidLoad()

  let customTabBar = // initialize a custom tab bar
  setValue(customTabBar, forKey: "tabBar")
}

UITabBarController will now happily replace its stock tab bar object with yours, letting you go about your business skinning your tab bar to your heart’s content.

Tagged with: