UITabBarController Subview Gotcha

By far the most view blog article that I have, and subsequent Github project, is my Universal iOS App Template.  Unfortunately, it has been a tad bit neglected. There were some memory leaks, still supported 3.2 and not iOS5 compatible.  Now that I am working from home I have dedicated part of my day to personal projects and the first order of business is to get the app template up-to-date.  Most of the work was just cleanup and minor tweaks.  One of the branches however required a little bit more work. The template that comes with TabBarController support. A few months ago I added in the feature of having a “Tweetie” style indicator slider.  In 3.2 - 4.x iOS everything worked fine.  In iOS5 the indicator was not initially centered in relation to the first TabBarItem, but the entire TabBar.  When you selected another TabBarItem the indicator would move, but not in the correct position either.

The number of subviews are different between the iOS4 and iOS5.

--- iOS5
2011-11-17 09:14:54.290 UniversalExample[8989:f803] view frame: {{0, 0}, {768, 1024}}
2011-11-17 09:14:54.293 UniversalExample[8989:f803] view frame: {{181, 1}, {76, 48}}
2011-11-17 09:14:54.294 UniversalExample[8989:f803] view frame: {{291, 1}, {76, 48}}
2011-11-17 09:14:54.296 UniversalExample[8989:f803] view frame: {{401, 1}, {76, 48}}
2011-11-17 09:14:54.297 UniversalExample[8989:f803] view frame: {{511, 1}, {76, 48}}

--- iOS4
2011-11-17 09:16:06.751 UniversalExample[9033:b303] view frame: {{181, 1}, {76, 48}}
2011-11-17 09:16:06.754 UniversalExample[9033:b303] view frame: {{291, 1}, {76, 48}}
2011-11-17 09:16:06.754 UniversalExample[9033:b303] view frame: {{401, 1}, {76, 48}}
2011-11-17 09:16:06.755 UniversalExample[9033:b303] view frame: {{511, 1}, {76, 48}}

I now confirmed that there indeed was a difference in how the center position was being calculated. In iOS5 the first subview is the entire frame of the view.  However, I didn’t know which view(sub or super) that it might be referring to.

The best uiview debugging tool for situations like this is the recursiveDescription method.  If you haven’t heard or used it before I suggest/encourage you read Oliver Drobnik’s blog on it. In summary it is a private method to iterate over a views hierarchy.

After calling this method on the subviews in both iOS versions I saw the culprit. The first subview of a UITabBarController is an UITabBarBackgroundView, which obviously is going to extended the entire length of the tab bar.

iOS4


iOS5


Why did Apple add this subview you might ask? They added it because of welcome changes to UIKit.  Since iOS 2.0 developers have needed the ability to customize many of the UI elements, but unfortunately there wasn’t a straight forward way to accomplish this. The categories and hacks that people came up with are pretty cool, but not maintainable. With iOS5, and updates to UIKit, you can customize background images, tint color, selected images, etc. to your heart’s desire.


In order to fix the iOS5 bug in my template I just had to add a quick runtime check on the OS version and increment the index by 1.

All is right with the world.