How to subclass UINavigationBar for a UINavigationController programmatically?

Viewed 18707

I'm using a custom drawRect function to draw on UINavigationBar across my application in iOS4, it doesn't use images, only CoreGraphics.

Since you can't implement drawRect in UINavigationBar category in iOS5, Apple is suggesting to subclass UINavigationBar.

How is it possible to replace the UINavigationBar with my subclass in UINavigationController (so it'll be compatible with iOS4 and iOS5) when the navigationBar property is read only?

@property(nonatomic, readonly) UINavigationBar *navigationBar

I'm not using XIBs in my application at all, so adding a UINavigationBar to a NIB and changing the class via InterfaceBuilder is not an option.

6 Answers

Had issues with answers 2-4 in iOS 4 (from AnswerBot's answer), and needed a way to load the UINavigationController programmatically (though the NIB method worked)... So I did this:

Created a Blank XIB file (don't set file owner), add a UINavigationController (give it your custom UINavigationController's class), change the UINavigationBar to your custom class (here it's CustomNavigationBar), then create the following custom class header (CustomNavigationController.h in this case):

#import <UIKit/UIKit.h>

@interface CustomNavigationController : UINavigationController
+ (CustomNavigationController *)navigationController;
+ (CustomNavigationController *)navigationControllerWithRootViewController:(UIViewController *)rootViewController;
@end

and custom implementation (CustomNavigationController.mm)

#import "CustomNavigationController.h"

@interface CustomNavigationController ()

@end

@implementation CustomNavigationController
+ (CustomNavigationController *)navigationController
{
    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"CustomNavigationController" owner:self options:nil];
    CustomNavigationController *controller = (CustomNavigationController *)[nib objectAtIndex:0];
    return controller;
}


+ (CustomNavigationController *)navigationControllerWithRootViewController:(UIViewController *)rootViewController
{
    CustomNavigationController *controller = [CustomNavigationController navigationController];
    [controller setViewControllers:[NSArray arrayWithObject:rootViewController]];
    return controller;
}

- (id)init
{
    self = [super init];
    [self autorelease]; // We are ditching the one they allocated.  Need to load from NIB.
    return [[CustomNavigationController navigationController] retain]; // Over-retain, this should be alloced
}

- (id)initWithRootViewController:(UIViewController *)rootViewController
{
    self = [super init];
    [self autorelease];
    return [[CustomNavigationController navigationControllerWithRootViewController:rootViewController] retain];
}
@end

Then you can just init that class instead of a UINavigationController, and you'll have your custom navigation bar. If you want to do it in a xib, change the class of UINavigationController and UINavigationBar inside of your XIB.

Related