So this is an old question, but I stumbled upon it when I was searching for something that sounds like this question, but is different. In hopes that it will help someone else (or that someone else will show me a better way)...
How do you implement a custom gradient on a UINavigationBar?
First, let's get our custom gradient the way we normally would (As a CALayer):
- (CALayer *)gradientBGLayerForBounds:(CGRect)bounds
{
CAGradientLayer * gradientBG = [CAGradientLayer layer];
gradientBG.frame = bounds;
gradientBG.colors = @[ (id)[[UIColor redColor] CGColor], (id)[[UIColor purpleColor] CGColor] ];
return gradientBG;
}
There we go, a gradient that looks like a questionable make-up choice of a punk rocker, which is good, as this code is for the hypothetical app I Have A Punk-Rocker With Questionable Tastes In My Pocket. That name me be a little too long..
Now I want this layer on my UINavigationBar, which should be easy ya? Just add it as a sublayer, right? The problem here is it will cover up the wonderful buttons and stuff that the UINavigationController gives you. That's bad.
Instead let's look at the wonderful convenience method we have in iOS5+ for altering the appearance of all the UINavigationBar(s) in our app:
[[UINavigationBar appearance] setBackgroundImage:SOME_IMAGE
forBarMetrics:UIBarMetricsDefault];
The only problem here is we don't have an UIImage, we have a CALayer. What's a punk-rocker enthusiast to do?
CALayer * bgGradientLayer = [self gradientBGLayerForBounds:ONE_OF_YOUR_NAV_CONTROLLERS.navigationBar.bounds];
UIGraphicsBeginImageContext(bgGradientLayer.bounds.size);
[bgGradientLayer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * bgAsImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
So now we've converted our CALayer to an UIImage (hopefully), so all that remains is to set it:
if (bgAsImage != nil)
{
[[UINavigationBar appearance] setBackgroundImage:bgAsImage
forBarMetrics:UIBarMetricsDefault];
}
else
{
NSLog(@"Failded to create gradient bg image, user will see standard tint color gradient.");
}
What I like about this solution is
- the centralized code (in the AppDelegate) for all UINavigationBar(s) in my app
- tintColor will still be honored for all the UINavigation buttons (back, edit, etc.)
- if the UIImage creation fails my UINavigationBar(s) will still honor the tintColor
- I don't have to depend on an actual image resource / easy to update
But I'm still not convinced it's the best way. So, enjoy if it helps you, let me know how to improve it if you can.
~ Thanks