Ever had to do an app with that magnificent center button that’s sticking gorgeously out of the TabBar? Then I bet you know that it’s not as simple as throwing that piece in the TabBarController as a subview. It may be working at first, but it’ll stab you in the back the first chance it gets.
Let’s take a look at this example:
We have a TabBar with two normal items and one knob item in the middle.
We’ll use a simple UITabBarController.
First things first, let’s create two UITabBarItem-s and move them out of the way. Let’s shift them for about 15pt.
This can be done either in the UITabBarController or the UITabBar subclass. I did it in the UITabBarController.
Next, where should we put that knob in? Here are the most common approaches I’ve seen so far:
The ‘UITabBarController, your view should have this’ approach
The most common (and easiest) way is to simply throw that knob into the view of the UITabBarController’s subclass.
While this seems pretty straightforward and actually works (at least at first) – brace yourself, troubles are coming.
‘Your mom is calling’ trouble:
The first problem is the In-Call status bar, which is basically the status bar expanding its height and consequentially moving the UITabBarController’s view down and thus moving the middle button with it:
The same happens with other status bar changes, such as Background recording and Background location usage (Google Maps).
‘Let’s hide you in the next screen’ trouble:
While one of the UITabBarController’s main features is that it is visible on multiple screens, you may want to hide it from time to time while pushing another view controller. Let’s see what happens if we check the “Hides bottom bar when pushed” property on the pushed view controller:
And the result:
Welp, the button doesn’t want to go away! The reason for this is because the middle button is rendered to the UITabBarController’s UILayoutContainerView, which is shared with the UINavigationController.
To bypass this issue, check out the next approach.
The ‘UITabBar, you should take this’ approach
A better way is to add the centered button to the TabBar:
This fixes the In-Call and hiding issues mentioned earlier, but leads to another issue – because the knob is bigger than the bounds of the TabBar, the overlapping part of the button isn’t tappable.
Now what? Don’t give up. There’s still hope.
Making the unclickable knob clickable again
Since the TabBar handles taps only inside its bounds, we’ll need to help him out a bit. For that we need to subclass the UITabBar directly. This will allow us to override the TabBar hitTest method. With that we can manually specify which views are tapped on a certain given point.
How can we know whether or not the certain given point is inside the knob? By simply calculating the distance of the point from the center of the knob – simple Pythagorean theorem. If the distance is less than the radius, the point is inside.
The final code in the hitTest then looks like:
If the point is inside the button, return the reference to the button, otherwise, ask the super to check for any other views – the UITabBarItems for example.
The result:
The whole project for download can be found on GitHub here.