Nav Color

Posted on Oct 23, 2013

In iOS 7, Apple changed the navigation bar to be semitransparent by default. In doing this, they pull down the saturation of the color you set as the barTintColor. This is a very bad thing. So bad that they fixed it with 7.0.3. That’s great moving forward, but they shipped 3 minor releases with the broken color behavior, and not all users upgrade minor point releases. What’s a developer to do?

UINavigationBar isn’t changing colors if you disable transluency, but in their infinate wisdom Apple didn’t make the transluency property available through UIAppearance, so you’d have to set it manually on every navigation bar in your app. Luckily we have one more trick up our sleave. It looks like the UINavigationBar is not changing image colors if you set an image as the background. But you don’t want to create a new image every time your designer changes their mind, so create a single pixel image in code! Put the following method into a category on UIImage:

+ (UIImage *)imageWithColor:(UIColor *)color
{
    CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, [color CGColor]);
    CGContextFillRect(context, rect);

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;
}

I allow my designers to specify a main theme color with a hex value, and have the following method in a Category on UIColor:

+ (UIColor *)colorFromHexString:(NSString *)hexString alpha:(float)alpha
{
    // Hex strings may optionally start with a #
    NSString *strippedString = [hexString stringByReplacingOccurrencesOfString:@"#" withString:@""];
    NSScanner *scanner = [NSScanner scannerWithString:strippedString];
    unsigned int rgbValue = 0;
    [scanner scanHexInt:&rgbValue];

    return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16)/255.0 green:((rgbValue & 0xFF00) >> 8)/255.0 blue:(rgbValue & 0xFF)/255.0 alpha:alpha];
}

Putting in all together, you can now set the background color of your UINavigationBar application wide using UIAppearance! I have an -[AppDelegate initializeAppearance] method I call from application:didFinishLaunchingWithOptions: which contains the following:

- (void)initializeAppearance
{
    // .... snip other app appearance code ...

    // ...snip getting color and alpha values from config
    NSString *hexColor = @"#007646";
    float alpha = 1.0;

    UIColor *barColor = [UIColor colorFromHexString:hexColor alpha:alpha];
    UIImage *backgroundImage = [UIImage imageWithColor:barColor];
    [[UINavigationBar appearance] setBackgroundImage:backgroundImage forBarMetrics:UIBarMetricsDefault];
}

Before:

Before Image

After:

After Image

I hope this helps anyone who has to support users on iOS 7.0 - 7.0.2.