Create an iOS custom TabBar with Swift

…writing the minimal amount of code and making the most of Storyboards.

I’m learning Swift (after developing iOS & Android apps for a few years with Titanium) and I was trying to build a custom TabBar with the minimal amount of effort. There are a lot of tutorials or examples out there but most of them involve writing a good amount of code and/or use advanced topics that for a beginner as myself might look a little intimidating.

One amazing example is the animated-tab-bar that teaches you (by looking at the code) about subclassing, protocols, extensions, animation, etc. Another is this simple tutorial that teaches you how to create a custom tab bar from scratch.

Both cases were a little overwhelming for me right now that I just started to learn so I thought it must be an easier/faster way to do this (I know, I’m lazy).

The idea is to reuse the UITabBarController that Xcode gives you when you create a new tabbed application.

So go create a new project, choose Tabbed Application and save it in a convenient place.

The first thing you need to do is to create a custom controller for your tab bar controller. You add a new Cocoa Touch Class file type to the project and you subclass it to UITabBarController. I named mine CustomTabBarController (duh!)

New custom UITabBarcontroller

Next step (DON’T forget!) is to set your tab bar controller’s class to this new custom controller you just created:

Select the correct Class for the tab bar controller

Now we are ready to create the custom tab bar which, you can imagine, will be an UIView that will hold (in this case) buttons which will be used to switch between tabs.

The funny thing is that the UITabBarController doesn’t allow you to drag anything from the library into its view (go on, try). It turns out however that Xcode gives you the possibility to create extra views in a controller which are UI elements available to the controller but not added into the scene hierarchy (you will need to add them yourself in the code, in a few you’ll see how).

So to do this, find the UIView element in the library and drag it in the dock of the scene (the top bar of the scene where the Controller, First Responder and Exit symbols are):

Add the UIView to the Scene Dock

You will see a placeholder positioned between the First Responder and Exit symbols. Once you drop it there it will show up as a small view “floating” above your scene.

Now you can handle this view like any other view in the controller, the only difference being that it won’t show when you run the app. Yet.

Just create an outlet for this extra view and attach to the view of the controller in the viewDidLoad method. You also have to set the width of the view to fill the parent as there is no way to add constraints using the storyboard (at least I couldn’t find how). The height is set in the Size Inspector.

Set the outlet, width and add the extra view as subview

The above image has the buttons already added but you get the idea. It also shows the outlet at line 13 connected to the extra view.

Drag two UIButtons in the extra view and in the Attributes Inspector set the Tag property to 0 for the First Tab button and 1 for the Second Tab button. We will use this Tag property to select the tab in our CustomTabBarController.

If you run the app now you should see something similar to the screenshot below (I changed the colours of the tabs to see clearly our extra view on top):

Ok, we just need to add the functionality and get rid of the original tab bar. This is really simple, add an action from the First Tab button, connect it to the Second Tab too, and then just tell the controller to set the selectedIndex to the button’s Tag. To get rid of the initial tab bar just select the Tab Bar in your controller and set it to Hidden in the Attributes Inspector.

This is how the final CustomTabBarController code looks like. Pretty neat if you ask me :)

import UIKit
class CustomTabBarController: UITabBarController {
  @IBOutlet var customTabBarView: UIView!
  override func viewDidLoad() {
super.viewDidLoad()
   customTabBarView.frame.size.width = self.view.frame.width
self.view.addSubview(customTabBarView)
}
  @IBAction func changeTab(sender: UIButton) {
self.selectedIndex = sender.tag
}
}

I intentionally omitted selected states for the custom tabs, images, etc because I think this is out of the scope of this post.

I’d really love to hear opinions from more experienced developers if this approach is “right”, if there are any drawbacks I’m not aware of, or any other ideas that could help improve the presented case.

Thank you for reading :)