Achieving bright, vivid colors for an iOS 7 transl

2019-01-04 15:02发布


iOS 7.1 UPDATE: Looks like the workaround for modifying the alpha channel in the UINavigationBar has been ignored in this update. Right now, the best solution seems to be to just 'deal with it' and hope that whatever color you choose can render a translucent effect. I am still looking into ways of getting around this.


iOS 7.0.3 UPDATE: The GitHub library we created has been updated to slightly work around this issue when using iOS 7.0.3. Unfortunately, there is no magic formula to support both colors created in iOS 7.0.2 and earlier and iOS 7.0.3. Seems like Apple improved the saturation, but at the cost of opacity (since the blurred translucency is dependant on the opacity level). I, along with a few others, are working on creating a much better fix for this.


I'm sure many people have already come across the problem where iOS 7 tends to desaturate the color of a UINavigationBar that is translucent.

My goal is to achieve a UINavigationBar with this tint color, but translucent:

UINavigationBar, Opaque

However, with translucency, I'm getting this. The background view is white, which I understand will make this view a bit lighter:

UINavigationBar, Translucent

Is there any way to achieve the original color while still having translucency? I've noticed Facebook has been able to get their bar to be their rich, blue color, as displayed here:

Facebook UINavigationBar, Translucent

..so I know there has to be some way. Background views obviously make a difference here, but most of their content is also gray/white. It seems that regardless of whatever bar tint color you put in, you are unable to get vivid colors under translucency.

Updated with solution.

Here's the solution that I ended up coming up with. I took aprato's solution and then encompassed the custom UINavigationBar within a UINavigationController subclass. I have created a repository that has this implementation listed below, along with an example app.

////////////////////////////
// CRNavigationBar.m
////////////////////////////

#import "CRNavigationBar.h"

@interface CRNavigationBar ()
@property (nonatomic, strong) CALayer *colorLayer;
@end

@implementation CRNavigationBar

static CGFloat const kDefaultColorLayerOpacity = 0.5f;
static CGFloat const kSpaceToCoverStatusBars = 20.0f;

- (void)setBarTintColor:(UIColor *)barTintColor {
    [super setBarTintColor:barTintColor];
    if (self.colorLayer == nil) {
        self.colorLayer = [CALayer layer];
        self.colorLayer.opacity = kDefaultColorLayerOpacity;
        [self.layer addSublayer:self.colorLayer];
    }
    self.colorLayer.backgroundColor = barTintColor.CGColor;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    if (self.colorLayer != nil) {
        self.colorLayer.frame = CGRectMake(0, 0 - kSpaceToCoverStatusBars, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) + kSpaceToCoverStatusBars);

        [self.layer insertSublayer:self.colorLayer atIndex:1];
    }
}

@end

////////////////////////////
// CRNavigationController.m
////////////////////////////

#import "CRNavigationController.h"
#import "CRNavigationBar.h"

@interface CRNavigationController ()

@end

@implementation CRNavigationController

- (id)init {
    self = [super initWithNavigationBarClass:[CRNavigationBar class] toolbarClass:nil];
    if(self) {
        // Custom initialization here, if needed.    
    }
    return self;
}

- (id)initWithRootViewController:(UIViewController *)rootViewController {
    self = [super initWithNavigationBarClass:[CRNavigationBar class] toolbarClass:nil];
    if(self) {
        self.viewControllers = @[rootViewController];
    }

    return self;
}

@end

16条回答
我想做一个坏孩纸
2楼-- · 2019-01-04 15:40

None of these hacks are required :). Simply set:

self.navigationController.navigationBar.translucent = NO;

For iOS 7, the default translucency has been kept to TRUE.

查看更多
小情绪 Triste *
3楼-- · 2019-01-04 15:41

is there a way to use @aprato solution without subclassing UINavigationBar.

In my project my main view is a UIViewController.

the problem is that the navigationController is a readonly property, is there a way to use you class with my project because i can't use : [[UINavigationController alloc] initWithNavigationBarClass:

thanks

查看更多
Luminary・发光体
4楼-- · 2019-01-04 15:49

Instead of creating your UIColor object in the RGB format, use HSB and increase the saturation parameter. (Credits to Sam Soffes who describes this method here)

navigationBar.barTintColor = [UIColor colorWithHue:0.555f saturation:1.f brightness:0.855f alpha:1.f];

Note: This solution is a tradeoff and doesn't work well for colors with high saturation.

To pick the HSB color from your design you can use a tool like ColorSnapper which allows you to simply copy the UIColor HSB format.

You can also try the UIColor Category (GitHub Link) from David Keegan to modify existing colors.

查看更多
▲ chillily
5楼-- · 2019-01-04 15:49

Theres a great Dropin UINavigationController replacement available from Simon Booth available at GitHub Here GitHub - C360NavigationBar

If you're backward supporting iOS6 do a check on the root view controller as such:

PatientListTableViewController *frontViewController = [[PatientListTableViewController alloc] init];

    UINavigationController *navViewController = [[UINavigationController alloc] initWithNavigationBarClass:[C360NavigationBar class] toolbarClass:nil];
if ([navViewController.view respondsToSelector:@selector(setTintColor:)]) {
    //iOS7
    [navViewController.view setTintColor:self.navBarTintColor];
    [[C360NavigationBar appearance] setItemTintColor:self.navBarItemTintColor];
} else {
    //iOS6
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:NO];
    navViewController.navigationBar.tintColor = self.navBarTintColor;
}
[navViewController pushViewController:frontViewController animated:NO];

self.window.rootViewController = navViewController;
查看更多
够拽才男人
6楼-- · 2019-01-04 15:51

One low-fi way would probably be pinning a UIView that is the height of the Navigation Bar to the top of the view behind the bar. Make that view the same color as the navigation bar but play with the alpha until you get the desired effects:

UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.navigationController.navigationBar.frame), 64)];
    backgroundView.backgroundColor = [UIColor colorWithRed:0.0 green:0.0 blue:1 alpha:.5];

[self.navigationController.view insertSubview:backgroundView belowSubview:self.navigationController.navigationBar];

UIView behind

enter image description here

(Changed color from lower examples to emphasis transparency. Transparency/blurring is more noticeable when in movement.)

Subclassing the UINavigationBar and placing that same view above the background but behind everything else will probably achieve similar results while being less hacky.


Another solution I've seen tossed around is playing with the alpha of the UINavigationBar:

self.navigationController.navigationBar.alpha = 0.5f;

Edit: Actually, after testing it seems like this doesn't provide the intend behavior (or any behavior):

.8 alpha

Navigation bar with .8 alpha

Unadjusted alpha

enter image description here

Obviously, you will only want to do this on iOS 7 devices. So, add some version check before you implement any of these.

查看更多
爷、活的狠高调
7楼-- · 2019-01-04 15:52

I came across this Q/A while trying to setup an uniformly colored navigation bar with transparency DISABLED on iOS 7.

After experimenting a while with barTintColor I figured out that a very easy way of having an opaque navigation bar is to make a single pixel image of the desired color, make a stretchable image out of it, and setting it to the backgroundImage of the navigation bar.

UIImage *singlePixelImage = [UIImage imageNamed:@"singlePixel.png"];
UIImage *resizableImage = [singlePixelImage resizableImageWithCapInsets:UIEdgeInsetsZero];
[navigationBar setBackgroundImage:resizableImage forBarMetrics:UIBarMetricsDefault]; 

Three lines of code, very simple and works BOTH on iOS 6 and iOS 7 (barTintColor is unsupported on iOS 6).

查看更多
登录 后发表回答