Adding a persistent ad banner to a UITabBar

By on February 8th, 2010 in iOS Comments (6)

Here’s a little tip for anyone that wants to add a persistent ad banner above the UITabBar to their tab navigation based iPhone app. I’ve seen a few apps do this so I was fairly surprised when a quick search of Google and StackOverflow turned up absolutely nothing. After all, it seems like it would be a fairly common thing to do. Perhaps I was looking in the wrong places, or this task is so basic that everyone else was able to magically intuit the correct procedure without having to look.

The trick is to notice that the UITabBarController’s view has two subviews:

  1. The UITabBar itself, exposed as the tabBar property.
  2. An undocumented/unexposed UITransitionView, which acts as the parent container view for your child UIViewController’s views.

So all we need to do is access the container and reduce its height by 50px or whatever the height of your ad banner is, and then we can add the ad banner to the UITabBarController’s view in the newly freed space above the tab bar.

Because this seems like a common task for anyone integrating an ad banner into a tab based iPhone app, I’ve written a simple, reusable, ad-network agnostic example class that takes care of this for you:

//  PersistentAdTabBarController.h
 
#import <UIKit/UIKit.h>
 
@protocol PersistentAdTabBarDelegate <NSObject>
// Should return the UIView to be used as the ad banner.
- (UIView *)getAdBanner;
@end
 
// UITabBarController that has room for a persistent ad banner above the UITabBar
@interface PersistentAdTabBarController : UITabBarController {
	UIView *adBanner;
	UIView *container;
	CGRect adBannerFrame;
	CGRect containerFrame;
	id <PersistentAdTabBarDelegate> delegate;
}
 
@property (nonatomic, retain) UIView *adBanner;
@property (nonatomic, retain) UIView *container;
@property (nonatomic) CGRect adBannerFrame;
@property (nonatomic) CGRect containerFrame;
@property (nonatomic, assign) id <PersistentAdTabBarDelegate> delegate;
 
// Shows the ad banner in the space above the tab bar. This should be called after your
// ad library tells you that a banner has been loaded.
- (void)showAdBanner;
// Hides the ad banner. This can be called if your ad library can't find an ad to display.
- (void)hideAdBanner;
 
@end
//  PersistentAdTabBarController.m
 
#import "PersistentAdTabBarController.h"
 
 
@implementation PersistentAdTabBarController
 
@synthesize adBanner;
@synthesize delegate;
@synthesize container;
@synthesize containerFrame;
@synthesize adBannerFrame;
 
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];
 
	self.adBanner = [delegate getAdBanner];
	self.adBannerFrame = adBanner.frame;
 
	// A UITabBarController's view has two subviews: the UITabBar and a container UITransitionView that is
	// used to hold the child views. Save a reference to the container.
	for (UIView *view in self.view.subviews) {
		if (![view isKindOfClass:[UITabBar class]]) {
			self.container = view;
			self.containerFrame = view.frame;
		}
	}
}
 
- (void)viewDidUnload {
	self.adBanner = nil;
	self.delegate = nil;
	self.container = nil;
	[super viewDidUnload];
}
 
- (void)dealloc {
	[adBanner release];
	[container release];
	[super dealloc];
}
 
- (void)showAdBanner {
	CGFloat containerHeight = containerFrame.size.height;
	CGFloat adBannerHeight = adBannerFrame.size.height;
 
	// Resize the frame of the container to add space for the ad banner
	container.frame = CGRectMake(0.0,0.0,320.0,containerHeight - adBannerHeight);
 
	// Place the ad banner above the tab bar but below the container
	adBanner.frame = CGRectMake(0.0,containerHeight - adBannerHeight,320.0,adBannerHeight);
	[self.view addSubview:adBanner];
}
 
- (void)hideAdBanner {
	// Resize the frame of the container to take up all available space
	container.frame = CGRectMake(0.0,0.0,320.0,containerFrame.size.height);
 
	// Remove the ad banner
	[adBanner removeFromSuperview];
}
 
@end

Ok, that probably was so simple that no one else had to look. Simply replace your UITabBarController with my fancy PersistentAdTabBarController and implement the delegate method getAdBanner, which should return the UIView for your ad banner of choice. When you are ready to display your ad (generally when your ad library tells you that it has managed to successfully load one), call showAdBanner. If yoou want to hide the ad (when your ad library tells you it can’t find any ads), you can use hideAdBanner to hide it.

Warning: In this example I make the assumption that the only two subviews of the UITabBarController’s view are the tabBar and the container view. Obviously, if this changes in a future release of the iPhone SDK, this will break. Use at your own peril!


  • http://www.vanille-media.de Mickey

    Hi Steven,

    thanks for your post, it works great – however we seem to have a problem with the banner not being pushed away when using the ‘hidesTabBarWhenPushed’ property of a navigation controller. Do you have any idea how to fix that?

  • http://www.vanille-media.de Mickey

    Couldn’t get this to work automagically, so I resorted to the TabViewController implementing the NavigationControllerDelegate and hiding/showing the banner depending on the hidesBottomBarWhenPushed property.

  • Raider

    Really stuck on…..”and implement the delegate method getAdBanner, which should return the UIView for your ad banner of choice.” Could you go into more detail here. Newbie here – I replaced my UITabBarController with the PersistentAdTabBarController and added -(UIView *) getAdBanner to my MainAppDelegate class (which creates a UIView and UIImageView…Adds image to View and returns View. However getAdBanner is never called?

  • http://www.success-ware.com Oded

    And no problems with app approval on AppStore?

    Thanks!

  • Aaron

    The ad overlaps the views which isn’t real good. Is there a way to push/resize each of the tabs views so that they don’t get covered by the ad banner?

  • Rglowaski

    Can you post a link of the app, so we can download it to see how it works.