为 iOS 7 半透明 UINavigationBar 实现明亮、生动的色彩
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18897485/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Achieving bright, vivid colors for an iOS 7 translucent UINavigationBar
提问by SpacePyro
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.1 更新:看起来在此更新中忽略了修改 UINavigationBar 中的 alpha 通道的解决方法。现在,最好的解决方案似乎是“处理它”,并希望您选择的任何颜色都可以呈现半透明效果。我仍在寻找解决此问题的方法。
iOS 7.0.3 UPDATE: The GitHub library we createdhas 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.
iOS 7.0.3 更新:我们创建的GitHub 库已经更新,在使用 iOS 7.0.3 时稍微解决了这个问题。不幸的是,没有神奇的公式来支持在 iOS 7.0.2 及更早版本和 iOS 7.0.3 中创建的颜色。似乎 Apple 提高了饱和度,但以不透明度为代价(因为模糊的半透明度取决于不透明度级别)。我和其他一些人正在努力为此创建一个更好的解决方案。
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.
我相信很多人已经遇到过这样的问题,即 iOS 7 倾向于降低半透明 UINavigationBar 的颜色。
My goal is to achieve a UINavigationBar with this tint color, but translucent:
我的目标是实现具有这种色调但半透明的 UINavigationBar:
However, with translucency, I'm getting this. The background view is white, which I understand will make this view a bit lighter:
但是,通过半透明,我得到了这个。背景视图是白色的,我理解这会使这个视图更亮一点:
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 已经能够让他们的酒吧成为他们丰富的蓝色,如下所示:
..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.
这是我最终想出的解决方案。我采用了aprato的解决方案,然后将自定义包含UINavigationBar
在一个UINavigationController
子类中。我创建了一个存储库,其中列出了下面列出的这个实现,以及一个示例 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
采纳答案by Anthony
iOS 7.0.3 UPDATE:As you see above 7.0.3 changed things. I've updated my gist. Hopefully this will just go away as people upgrade.
iOS 7.0.3 更新:正如你在上面看到的 7.0.3 改变了一些东西。我已经更新了我的要点。希望这会随着人们升级而消失。
Original Answer:I ended up with a hack combining the two of the other answers. I'm subclassing UINavigationBar and adding a layer to the back with some extra space to cover if any of the various height status bars are up. The layer gets adjusted in layout subviews and the color changes whenever you set barTintColor.
原始答案:我最终结合了其他两个答案。我正在继承 UINavigationBar 并在后面添加一个层,如果各种高度状态栏中的任何一个出现,则有一些额外的空间来覆盖。图层会在布局子视图中进行调整,并且每当您设置 barTintColor 时颜色都会发生变化。
Gist: https://gist.github.com/aprato/6631390
要点:https: //gist.github.com/aprato/6631390
setBarTintColor
设置BarTintColor
[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);
}
回答by Bhavesh
The behavior of tintColor for bars has changed on iOS 7.0. It no longer affects the bar's background and behaves as described for the tintColor property added to UIView. To tint the bar's background, please use -barTintColor.You can use following code to make the app work with both ios6 and ios7.
条形的 tintColor 行为在 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 is a macro which is defined in pch file as follows.
IS_IOS7 是一个宏,在 pch 文件中定义如下。
#define IS_IOS7 ([[UIDevice currentDevice].systemVersion floatValue] >= 7.0)
回答by Jamie Hamick
I didn't come up with this solution but it seems to work fairly well. I just added it to viewDidLoad on my subclass of UINavigationController.
我没有想出这个解决方案,但它似乎工作得很好。我只是将它添加到 UINavigationController 子类上的 viewDidLoad。
Source: https://gist.github.com/alanzeino/6619253
来源: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];
回答by Kevin
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
导航栏的高度固定到栏后面的视图顶部。使该视图与导航栏具有相同的颜色,但使用 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 behind
后面的 UIView
(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.
子类化UINavigationBar
并将相同的视图放置在背景之上但在其他所有事物之后可能会获得类似的结果,同时不那么笨拙。
Another solution I've seen tossed around is playing with the alpha of the UINavigationBar
:
我见过的另一个解决方案是使用 alpha 的UINavigationBar
:
self.navigationController.navigationBar.alpha = 0.5f;
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
.8 阿尔法
Unadjusted alpha
未调整的阿尔法
Obviously, you will only want to do this on iOS 7 devices. So, add some version checkbefore you implement any of these.
显然,您只想在 iOS 7 设备上执行此操作。因此,在实现其中任何一个之前,添加一些版本检查。
回答by bernhard
Instead of creating your UIColor object in the RGBformat, use HSBand increase the saturation parameter. (Credits to Sam Soffeswho describes this method here)
不要以RGB格式创建 UIColor 对象,而是使用HSB并增加饱和度参数。(感谢在此处描述此方法的Sam Soffes)
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 ColorSnapperwhich allows you to simply copy the UIColor HSB format.
要从您的设计中选择 HSB 颜色,您可以使用ColorSnapper 之类的工具,它允许您简单地复制 UIColor HSB 格式。
You can also try the UIColor Category (GitHub Link) from David Keeganto modify existing colors.
您还可以尝试使用David Keegan的 UIColor Category ( GitHub Link)来修改现有颜色。
回答by smad
The problem has now been fixed by Apple in the new 7.0.3 release.
该问题现已由 Apple 在新的 7.0.3 版本中修复。
回答by Allen Hsu
I've improved your code in my fork: https://github.com/allenhsu/CRNavigationController
我在我的 fork 中改进了你的代码:https: //github.com/allenhsu/CRNavigationController
With my modification, the result color on screen (picked on white background) will be exactly the same value passed into setBarTintColor
. I think it's an amazing solution.
通过我的修改,屏幕上的结果颜色(在白色背景上选择)将与传递给setBarTintColor
. 我认为这是一个了不起的解决方案。
回答by Mr. T
I used @aprato's solution but found a few corner cases where the new layers from new VCs (eg. UINavigationItemButtonViews
, UINavigationItemViews
, etc) would be automatically inserted into a position below the extraColorLayer
(which would cause those title or button elements to be affected by the extraColorLayer
and thus fainter in color than they normally would be). So I adjusted @aprato's solution to force the extraColorLayer
to stay at the index position 1. At index position 1, the extraColorLayer
stays right above the _UINavigationBarBackground
, but underneath everything else.
我用@ aprato的解决方案,但发现其中来自新的VC的新层(例如,几拐角情况UINavigationItemButtonViews
,UINavigationItemViews
等等)将被自动地插入到下面的一个位置extraColorLayer
(这将导致由受影响的那些标题或按钮元素extraColorLayer
,因此颜色比平时更暗)。因此,我调整了@aprato 的解决方案以强制extraColorLayer
保持在索引位置 1。在索引位置 1 处,extraColorLayer
保持在 的正上方_UINavigationBarBackground
,但位于其他所有位置的下方。
Here's my class implementation:
这是我的类实现:
- (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
}
回答by bryguy1300
On a related note, you can set your title text color (with shadow) easily via:
在相关说明中,您可以通过以下方式轻松设置标题文本颜色(带阴影):
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];
回答by rishabh
None of these hacks are required :). Simply set:
不需要这些黑客:)。简单设置:
self.navigationController.navigationBar.translucent = NO;
For iOS 7, the default translucency has been kept to TRUE.
对于 iOS 7,默认半透明已保持为 TRUE。