Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
293 views
in Technique[技术] by (71.8m points)

iphone - UINavigationBar tintColor with gradient

I'd like to change programmaticaly the tintColor of a UINavigationBar and keep the gradient as in Interface Builder.

When I change the tintColor in my code, the gradient disappears but when I change the tintColor in Interface Builder, the gradient is kept.

Any ideas?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...