I wanted a custom UINavigationBar background image too, and ended up solving it by:
- In the UINavigationController's initialisation, I created a CALayer that had
contents
set to the background image, and the frame set accordingly.
- I added that layer to the UINavigationBar's layer (at index 0, in the background):
[self.navigationBar.layer insertSublayer:imageLayer atIndex:0]
At this point, it looks okay at first, but if you do any navigation, labels and buttons disappear behind the 'background' layer. So,
- I created a subclass of CALayer that changed the behaviour of insertSublayer:atIndex: so that no layers are inserted beneath the background layer.
Like this:
@implementation CTNavigationBarLayer
- (void)insertSublayer:(CALayer *)layer atIndex:(unsigned)idx {
if ( idx == 0 ) idx = 1;
[super insertSublayer:layer atIndex:idx];
}
- (void)addBackgroundLayer:(CALayer*)layer {
[super insertSublayer:layer atIndex:0];
}
@end
- Using a category on UINavigationBar, I overloaded the
+layerClass
method to return [CTNavigationBar class]
, so the navigation bar uses the custom layer.
Of course, this changes the behaviour of all UINavigationBars in your app, so if this isn't what you want, you'd want to seek an alternate way. You could subclass UINavigationBar, but then the only way to get that subclass to be used in a UINavigationController is via IB (or do some rather interesting mucking about to do it programmatically)
- Finally, back in the UINavigationController initialisation, I replaced the layer insertion with a call to the
addBackgroundLayer:
method I wrote.