为iOS 7半透明UINavigationBar实现明亮生动的色彩


iOS 7.1更新 :看起来修改UINavigationBar中的alpha通道的解决方法在此更新中被忽略。 现在,最好的解决办法似乎是“处理它”,并希望你select的任何颜色都可以产生半透明的效果。 我仍在研究如何解决这个问题。


iOS 7.0.3更新 : 我们创build的GitHub库已经更新,以稍微解决这个问题,当使用iOS 7.0.3。 不幸的是,在iOS 7.0.2和更早版本以及iOS 7.0.3中都不支持这两种颜色。 似乎苹果改善了饱和度,但代价是不透明度(因为模糊的半透明度取决于不透明度水平)。 我和其他一些人正在努力为此创造一个更好的解决scheme。


我相信很多人已经遇到了iOS 7倾向于使UINavigationBar颜色变得半透明的问题。

我的目标是实现一个UINavigationBar与这个色调,但半透明:

UINavigationBar,不透明

但是,半透明,我得到这个。 背景视图是白色的,据我了解,这个视图会变得更轻:

UINavigationBar,半透明

有没有办法在保持透明的同时达到原有的色彩? 我注意到Facebook已经能够让他们的酒吧成为他们丰富的蓝色,如下所示:

Facebook UINavigationBar,半透明

所以我知道必须有某种方法。 背景视图显然在这里有所作为,但其大部分内容也是灰色/白色。 看起来,无论你穿什么色调的颜色,你都不会在半透明的情况下得到鲜艳的色彩。

更新与解决scheme。

这是我最终提出的解决scheme。 我采取了aprato的解决scheme,然后在UINavigationController子类中包含自定义的UINavigationController 。 我创build了一个具有下面列出的实现的存储库,以及一个示例应用程序 。

 //////////////////////////// // 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 

iOS 7.0.3更新:正如你所看到的7.0.3以上改变的东西。 我已经更新了我的要点。 希望这会随着人们升级而消失。

原来的答案:我结束了与其他两个答案的结合。 我inheritanceUINavigationBar并添加一个图层到后面,如果任何一个不同的高度状态条都弹起来了,那么还需要额外的空间来覆盖它。 在布局子视图中调整图层,每当设置barTintColor时颜色都会更改。

要点: https : //gist.github.com/aprato/6631390

setBarTintColor

  [super setBarTintColor:barTintColor]; if (self.extraColorLayer == nil) { self.extraColorLayer = [CALayer layer]; self.extraColorLayer.opacity = self.extraColorLayerOpacity; [self.layer addSublayer:self.extraColorLayer]; } self.extraColorLayer.backgroundColor = barTintColor.CGColor; 

layoutSubviews

  [super layoutSubviews]; if (self.extraColorLayer != nil) { [self.extraColorLayer removeFromSuperlayer]; self.extraColorLayer.opacity = self.extraColorLayerOpacity; [self.layer insertSublayer:self.extraColorLayer atIndex:1]; CGFloat spaceAboveBar = self.frame.origin.y; self.extraColorLayer.frame = CGRectMake(0, 0 - spaceAboveBar, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) + spaceAboveBar); } 

tintColor for bars的行为在iOS 7.0上发生了变化。 它不再影响酒吧的背景和行为描述添加到UIView的tintColor属性。 要调整酒吧的背景,请使用-barTintColor。您可以使用以下代码使应用程序可以同时使用ios6和ios7。

 if(IS_IOS7) { self.navigationController.navigationBar.barTintColor = [UIColor blackColor]; self.navigationController.navigationBar.translucent = NO; } else { self.navigationController.navigationBar.tintColor = [UIColor blackColor]; } 

IS_IOS7是一个在pch文件中定义的macros,如下所示。

 #define IS_IOS7 ([[UIDevice currentDevice].systemVersion floatValue] >= 7.0) 

我没有提出这个解决scheme,但似乎工作得很好。 我只是把它添加到我的UINavigationController的子类viewDidLoad。

来源: https : //gist.github.com/alanzeino/6619253

 // cheers to @stroughtonsmith for helping out with this one UIColor *barColour = [UIColor colorWithRed:0.13f green:0.14f blue:0.15f alpha:1.00f]; UIView *colourView = [[UIView alloc] initWithFrame:CGRectMake(0.f, -20.f, 320.f, 64.f)]; colourView.opaque = NO; colourView.alpha = .7f; colourView.backgroundColor = barColour; self.navigationBar.barTintColor = barColour; [self.navigationBar.layer insertSublayer:colourView.layer atIndex:1]; 

一个low-fi的方式可能是固定一个UIView ,这是导航栏的高度,在酒吧后面的视图的顶部。 使该视图与导航栏颜色相同,但使用alpha直到获得所需的效果:

 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后面

在这里输入图像描述

(从较低的例子改变颜色到强调透明度。移动时透明度/模糊更明显。)

UINavigationBar子类化,并将相同的视图置于背景之上,但放在其他所有内容之后,可能会获得类似的结果,而不那么晦涩。


我见过的另一个解决scheme是玩UINavigationBar的alpha:

 self.navigationController.navigationBar.alpha = 0.5f; 

编辑:其实,经过testing,似乎这不提供意图的行为(或任何行为):

.8 alpha

导航栏与.8阿尔法

未经调整的阿尔法

在这里输入图像描述

显然,你只会想在iOS 7设备上这样做。 因此,在执行任何这些之前添加一些版本检查 。

不要以RGB格式创buildUIColor对象,请使用HSB并增加饱和度参数。 (感谢Sam Soffes 在这里描述这种方法)

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

注意:这个解决scheme是一个折衷,并且对于高饱和度的颜色不适用。

要从您的devise中selectHSB颜色,您可以使用像ColorSnapper这样的工具,它允许您简单地复制UIColor HSB格式。

您也可以尝试David Keegan的UIColor类别( GitHub链接 )来修改现有的颜色。

苹果已经在新的7.0.3版本中解决了这个问题。

我使用@ aprato的解决scheme,但发现一些angular落的情况下,来自新VC(例如UINavigationItemButtonViewsUINavigationItemViews等)的新图层将被自动插入到extraColorLayer下面的位置(这将导致这些标题或button元素受到影响extraColorLayer ,因此颜色比通常情况下变淡)。 所以我调整了@ aprato的解决scheme来强制extraColorLayer停留在索引位置1.在索引位置1, extraColorLayer保持在_UINavigationBarBackground ,但在其他所有的下方。

这是我的类实现:

 - (void)setBarTintColor:(UIColor *)barTintColor { [super setBarTintColor:barTintColor]; if (self.extraColorLayer == nil) { self.extraColorLayer = [CALayer layer]; self.extraColorLayer.opacity = kDefaultColorLayerOpacity; [self.layer insertSublayer:self.extraColorLayer atIndex:1]; // This way the text comes out clear } self.extraColorLayer.backgroundColor = barTintColor.CGColor; } - (void)layoutSubviews { [super layoutSubviews]; if (self.extraColorLayer != nil) { self.extraColorLayer.frame = CGRectMake(0, 0 - kSpaceToCoverStatusBars, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) + kSpaceToCoverStatusBars); } } - (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview { [super insertSubview:view aboveSubview:siblingSubview]; [self.extraColorLayer removeFromSuperlayer]; [self.layer insertSublayer:self.extraColorLayer atIndex:1]; // This way the text comes out clear } - (void)insertSubview:(UIView *)view atIndex:(NSInteger)index { [super insertSubview:view atIndex:index]; [self.extraColorLayer removeFromSuperlayer]; [self.layer insertSublayer:self.extraColorLayer atIndex:1]; // This way the text comes out clear } - (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview { [super insertSubview:view belowSubview:siblingSubview]; [self.extraColorLayer removeFromSuperlayer]; [self.layer insertSublayer:self.extraColorLayer atIndex:1]; // This way the text comes out clear } 

我改进了我的fork中的代码: https : //github.com/allenhsu/CRNavigationController

随着我的修改,屏幕上的结果颜色(在白色背景上挑选)将完全相同的值传递给setBarTintColor 。 我认为这是一个了不起的解决scheme。

没有这些黑客是必需的:)。 简单地设置:

 self.navigationController.navigationBar.translucent = NO; 

对于iOS 7,默认的半透明度保持为TRUE。


在相关说明中,您可以通过以下方式轻松设置标题文本的颜色(带阴影):

 NSShadow *titleShadow = [[NSShadow alloc] init]; titleShadow.shadowOffset = CGSizeMake(0.0f, -1.0f); titleShadow.shadowColor = [UIColor blackColor]; NSDictionary *navbarTitleTextAttributes = @{NSForegroundColorAttributeName: [UIColor whiteColor], NSShadowAttributeName: titleShadow}; [[UINavigationBar appearance] setTitleTextAttributes:navbarTitleTextAttributes]; 

我偶然发现这个问题,同时尝试在iOS 7上设置透明度为DISABLED的统一颜色的导航栏。

在用barTintColor试验了一段时间之后,我发现有一个不透明导航栏的简单方法就是制作一个具有所需颜色的单个像素图像,制作一个可伸缩的图像,并将其设置为导航栏的backgroundImage 。

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

三行代码,非常简单,适用于iOS 6和iOS 7(barTintColor在iOS 6上不受支持)。

Theres一个很好的Dropin UINavigationControllerreplace可从GitHub的Simon Booth获得在这里GitHub – C360NavigationBar

如果您向后支持iOS6,请在根视图控制器上进行检查:

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; 

正如上面提到的 @bernhard ,可能会使色条颜色饱和以获得所需的导航栏外观。

我为这种调整写了一个BarTintColorOptimizer实用程序 。 它优化了半透明条色的颜色,使条的实际颜色与iOS 7.x及更高版本中的所需颜色相匹配。 看这个答案的细节。

坦率地说,以上的答案可能是正确的,但下面的技巧很容易为我工作。

 // this is complete 100% transparent image self.imageBlack = [[UIImage imageNamed:@"0102_BlackNavBG"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 2, 0, 2) resizingMode:UIImageResizingModeStretch]; // this is non-transparent but iOS7 // will by default make it transparent (if translucent is set to YES) self.imageRed = [[UIImage imageNamed:@"0102_RedNavBG"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 2, 0, 2) resizingMode:UIImageResizingModeStretch]; // some navigation controller [nvCtrLeft.navigationBar setBackgroundImage:self.imageRed forBarMetrics:UIBarMetricsDefault]; // some another navigation controller [nvCtrCenter.navigationBar setBackgroundImage:self.imageRed forBarMetrics:UIBarMetricsDefault]; 

这里是用于self.imageRedself.imageBlack的图像。

< self.imageBlack >黑色的图像是在这个括号将不会被看到,因为它是透明的:)

< self.imageRed >红色图像在这个括号里。

有没有一种方法来使用@aprato解决scheme没有inheritanceUINavigationBar。

在我的项目中,我的主视图是一个UIViewController。

问题是navigationController是一个只读属性,有没有办法使用你的类与我的项目,因为我不能使用: [[UINavigationController alloc] initWithNavigationBarClass:

谢谢

一个简单的方法来获得你想要的颜色正在使用

  [<NAVIGATION_BAR> setBackgroundImage:<UIIMAGE> forBarPosition:<UIBARPOSITION> barMetrics:<UIBARMETRICS>]; 

只要你的图像有一些阿尔法,半透明将工作,你可以通过更改图像设置阿尔法。 这只是在iOS7中添加的。 垂直图像的宽度和高度为640x88px(如果您希望在状态栏下方添加20,则为88)。