Question

I have a few UIToolbars throughout my app. I want each one to have a different background. Here is an example of a Category I have:

#import "UIToolbar+NavBarAdditions.h"


@implementation UIToolbar (Addition)
- (void) drawRect:(CGRect)rect {
    UIImage *barImage = [UIImage imageNamed:@"rowbg.png"];
    [barImage drawInRect:rect];
}
@end

I have a few images rowbg1, rowbg2 etc etc that I want to use for other UIToolbars that are inside of my app. How can I choose which category to use for the respective toolbar?

Was it helpful?

Solution

Change a toolbar background

Using a subclass

A category changes all UIToolbar classes. If you need different toolbars, let each client be in charge of setting the image:

@interface UIBgToolbar : UIToolbar {
@private
    UIImage *_background;
}
@end
@implementation UIBgToolbar
- (id)initWithFrame:(CGRect)aRect imagen:(UIImage*)image {
    if (self = [super initWithFrame:aRect]){
        _background = [image retain];
    }
    return self;
}
- (void) drawRect:(CGRect)rect {
    UIImage *barImage = _background;
    [barImage drawInRect:rect];
}
-(void)dealloc {
    [_background release];
    [super dealloc];
}
@end

Usage:

UIImage *bg = [UIImage imageNamed:@"bar_bottom.png"];
// 416 = 480 - status bar (20) - navigation bar (44)
CGRect rect = CGRectMake(0, 416-bg.size.height, bg.size.width, bg.size.height);
UIBgToolbar *toolbar = [[UIBgToolbar alloc] initWithFrame:rect imagen:bg];
[self.view addSubview:toolbar];
[toolbar release];

Using a subview

This is an alternative way that adds a subview and doesn't need subclasses or categories:

UIImage *bg = [UIImage imageNamed:@"bar_bottom.png"];
// 416 = 480 - status bar (20) - navigation bar (44)
CGRect rect = CGRectMake(0, 416-bg.size.height, bg.size.width, bg.size.height);
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:rect];

UIImageView *background = [[[UIImageView alloc] initWithImage:bg] autorelease];
background.frame = toolbar.bounds;
background.autoresizingMask = UIViewAutoresizingFlexibleWidth;
BOOL isIOS5 = [[[UIDevice currentDevice] systemVersion] intValue] >= 5;
toolbar insertSubview:background atIndex: (isIOS5 ? 1 : 0)];

[self.view addSubview:toolbar];
[toolbar release];

Making the background transparent.

Don't use this unless you really need a transparent background.

@interface UITransparentToolBar : UIToolbar
@end
@implementation UITransparentToolBar
- (void)drawRect:(CGRect)rect {
    [[UIColor clearColor] set];
    CGContextFillRect(UIGraphicsGetCurrentContext(), rect);
}
@end

Usage:

// create the toolbar
UIImage *bg = [UIImage imageNamed:@"bar_bottom.png"];
// 416 = 480 - status bar (20) - navigation bar (44)
CGRect rect = CGRectMake(0, 416-bg.size.height, bg.size.width, bg.size.height);
UIBgToolbar *toolbar = [[UIBgToolbar alloc] initWithFrame:rect];

// add the background
// self.backgroundColor = [UIColor clearColor];
UIImageView *background = [[UIImageView alloc] initWithImage:bg];
background.frame = toolbar.bounds;
background.autoresizingMask = UIViewAutoresizingFlexibleWidth;
BOOL isIOS5 = [[[UIDevice currentDevice] systemVersion] intValue] >= 5;
[toolbar insertSubview:background atIndex: (isIOS5 ? 1 : 0)];

[self.view addSubview:toolbar];
[toolbar release];

Change a navigation bar

Navigation bar background

Use Noah's code in a category.

Using a subclass is also possible:

  • Create a UINavigationToolbar subclass containing the drawRect method from Noah's answer. - Select your MainWindow.XIB, select "Navigation Bar", press ⌥⌘3 to (show Identity Inspector), and change the class to the class you just created.
  • Also while in IB, press ⌥⌘4 (show Attributes Inspector) and set a number in the field Tag. If you look at Noah's code, that number decides which image to use.

Navigation bar toolbar background

Same thing as for a normal toolbar but using a category because the navigation toolbar is read-only:

// UIToolbar.h
@interface UIToolbar (Transparency)
- (void)drawRect:(CGRect)rect;
@end
// UIToolbar.m
#import "TransparentToolbar.h"
@implementation UIToolbar (Transparency)
- (void)drawRect:(CGRect)rect {
    [[UIColor clearColor] set];
    CGContextFillRect(UIGraphicsGetCurrentContext(), rect);
}
@end

Usage:

// bar_bottom_bumped.png is a toolbar image with transparency
UIImage *bg = [UIImage imageNamed:@"bar_bottom_bumped.png"];
UIImageView *background = [[UIImageView alloc] initWithImage:bg];
background.frame = self.navigationController.toolbar.bounds;
background.autoresizingMask = UIViewAutoresizingFlexibleWidth;
BOOL isIOS5 = [[[UIDevice currentDevice] systemVersion] intValue] >= 5;
self.navigationController.toolbar.backgroundColor = [UIColor clearColor];
[self.navigationController.toolbar insertSubview:background atIndex: (isIOS5 ? 1 : 0)];

OTHER TIPS

If you’re creating the toolbars yourself—in IB or through code—then Jano’s solution is mostly right, though I disagree with the idea of making it transparent: you should avoid doing unnecessary blending. If you need to replace the toolbars created by a navigation controller, though, you do need to use a category rather than subclassing. You can use your existing implementation; you just need to set a different tag on each of the toolbars you want to have a different appearance, then check that value in your -drawRect:. In other words, your view controller should have something like this:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    UIToolbar *toolbar = self.navigationController.toolbar;
    toolbar.tag = 3; // different value for each controller, or however you want to choose the toolbar
    [toolbar setNeedsDisplay];
}

and your toolbar category should have something like this:

- (void)drawRect:(CGRect)r
{
    UIImage *barImage = nil;
    switch(self.tag)
    {
        case 1:
            barImage = [UIImage imageNamed:@"rowbg.png"];
            break;
        case 3:
            barImage = [UIImage imageNamed:@"something else.png"];
            break;
    }

    [barImage drawInRect:self.bounds];
}

You should use subclassing instead of categories.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top