Ios – How to subclass a UITabBarController and replace its UITabBar view

iosiphoneobjective-c

I need to subclass a UITabBarController so that I can completely replace the UITabBar view with a custom view that I can hopefully produce in the interface builder. I tried but am not succeeding.

First, I created a subclass of UITabBarController along with a xib. I deleted the default view in the xib, and replaced it with a new one that was only 60px tall (the size of my tabbar). I dragged the necessary buttons onto it, and configured the .h file like so:

@interface ToolbarViewController : UITabBarController

@property (strong, nonatomic) IBOutlet UIView *tabBarView;

@property (strong, nonatomic) IBOutlet UIButton* firstButton;
@property (strong, nonatomic) IBOutlet UIButton* secondButton;

@end

My xib looks like this:

Xcode screenshot of the tabbar xib

When I launch the app, I see an empty space at the bottom made for the tab bar, but I am not seeing an actual tab bar:

App screenshot of the tabbar at runtime

Update: I realize that I'm not actually launching the xib file in the .m file. Anyone know how I can do this properly?

Best Solution

There are various different solutions for adding a custom set of buttons to a custom tab bar controller subclass. I've done it years ago following this guide: http://idevrecipes.com/2010/12/16/raised-center-tab-bar-button/.

The idea is to add a custom UIView over the tab bar of your UITabBarController subclass. The CustomTabBarController class doesn't have to have a xib. Instead, I have a subclass of UIView that can either be programmatically laid out, or created using a xib for a UIView. Here's the header file for my CustomTabBarView class:

@interface CustomTabBarView : UIView
{
    CALayer *opaqueBackground;
    UIImageView *tabBG;

    IBOutlet UIButton *button0;
    IBOutlet UIButton *button1;
    IBOutlet UIButton *button2;
    NSArray *tabButtons;

    int lastTab;
}
@property (nonatomic, weak) id delegate;

-(IBAction)didClickButton:(id)sender;

You'll either connect the desired buttons to button0, button1, button2, etc in the xib file, or do it programmatically on init for the view. Note that this is the UIView subclass.

In CustomTabBarView.m:

-(IBAction)didClickButton:(id)sender {
    int pos = ((UIButton *)sender).tag;
    // or some other way to figure out which tab button was pressed

    [self.delegate setSelectedIndex:pos]; // switch to the correct view
}

Then in your CustomTabBarController class:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    tabView = [[CustomTabBarView alloc] init];
    tabView.delegate = self;
    tabView.frame = CGRectMake(0, self.view.frame.size.height-60, 320, 60);
    [self.view addSubview:tabView];
}

When the buttons are clicked in the CustomTabBarView, it will call its delegate function, in this case the CustomTabBarController. The call is the same function as if you clicked on a tab button in the actual tab bar, so it will jump to the tabs if you have set up the CustomTabBarController correctly like a normal UITabBarController.

Oh, on a slightly separate note, the correct way to add a custom xib as the interface for a subclass of UIView:

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil];
        UIView *mainView = [subviewArray objectAtIndex:0];

        //Just in case the size is different (you may or may not want this)
        mainView.frame = self.bounds;

        [self addSubview:mainView];
    }
    return self;
}

In the xib file, make sure the File's Owner has its Custom class set as CustomTabBarView.

Related Question