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


172

iOS 7.1更新:在此更新中,似乎已忽略了用于修改UINavigationBar中的Alpha通道的解决方法。目前,最好的解决方案似乎是“处理”,并希望您选择的任何颜色都能呈现半透明的效果。我仍在研究解决此问题的方法。


iOS 7.0.3更新:使用iOS 7.0.3时,我们创建GitHub库已更新为可以稍微解决此问题。不幸的是,没有一种魔术公式可以支持在iOS 7.0.2和更低版本以及iOS 7.0.3中创建的两种颜色。好像苹果公司提高了饱和度,但是却以不透明度为代价(因为模糊的半透明性取决于不透明度)。我和其他一些人正在努力为此创建更好的解决方案。


我敢肯定,很多人已经遇到了iOS 7倾向于使半透明的UINavigationBar的颜色不饱和的问题。

我的目标是使用这种色调但半透明的颜色实现UINavigationBar:

UINavigationBar,不透明

但是,半透明,我明白了。背景视图为白色,据我所知,它将使该视图更浅:

UINavigationBar,半透明

有什么方法可以在保持半透明的同时获得原始颜色?我注意到Facebook能够使其条形成为其丰富的蓝色,如下所示:

Facebook UINavigationBar,半透明

..所以我知道一定有办法。背景视图显然在这里有所不同,但是它们的大多数内容也是灰色/白色。看来,无论您使用什么颜色,您都无法在半透明状态下获得鲜艳的色彩。

更新了解决方案。

这是我最终想到的解决方案。我采用了aprato的解决方案,然后将该自定义包含UINavigationBar在一个UINavigationController子类中。我创建了一个存储库,该存储库在下面列出了此实现以及一个示例应用程序

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

Facebook iOS7 UINAvigationBar不透明吗?
Vinzzz 2013年

不会,它比默认的iOS透明得多。更好,IMO。
凯文

Facebook NavigationBar不透明
LE SANG

7
它绝对是半透明的。请参阅我编辑后的回复。
SpacePyro 2013年

2
@Odelya -这是不以获得正确的颜色的溶液中,而是以校正的亮度的溶液UINavigationBar时在IOS 7.暴露于半透明尽可能最佳
SpacePyro

Answers:


52

iOS 7.0.3更新:如您所见,以上7.0.3更改了某些内容。我已经更新了要点。希望随着人们的升级,这种情况将消失。

原始答案: 我最终遭到黑客攻击,将其他两个答案结合在一起。我对UINavigationBar进行了子类化,并在后面添加了一层额外的空间来覆盖各种高度状态栏中的任何一条。每当设置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);
  }

您在ViewController的哪里实现的?在viewDidLoad下?
杰里米

这很漂亮!我决定将其添加到我的UINavigationController子类中。这里有一个要点它为那些有兴趣谁在具有自定义UINavigationBar内的UINavigationController
SpacePyro

@Jeremy像SpacePyro一样,我有一个导航控制器子类(就像我以前使用pre 7进行UIAppearance定位的栏一样),该类可以重写initWithRootViewController以使用它。我已经更新了要点
安东尼

嗯...好吧..我想我需要在整个测试项目中都看到这一点,才能完全理解您的意思。我可以在下面复制timeuser的示例,但是我对此还是有点陌生​​。
杰里米

1
@ Mr.T谢谢!当我写的时候它还没有推送:)但是我现在更新了它,增加了UIAppearance的不透明性和对NSCoding的支持
Anthony

10

在iOS 7.0上,酒吧的tintColor行为已更改。它不再影响条形的背景,并且行为与添加到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文件中定义的宏,如下所示。

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

9

我没有提出这个解决方案,但它似乎工作得很好。我只是将其添加到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];

1
将新的View Controller推入Navigation控制器后,所有条形按钮项都将移动到此透明层下。
埃文·戴维斯

标题也被此透明层所遮盖。
Nick Locking

我写了这个要点。评论是正确的。当按下新的视图控制器时,或者将按钮项推到下面,或者子层继承了的alpha colourView。我分叉了另一个答案,并在一个新的下拉菜单中修复了一些问题:github.com/alanzeino/AZColoredNavigationBar
Alan Zeino

通过选择“半透明黑色导航栏”样式,我可以将文本设置为白色...这确实帮了我大忙。还要设置yourBar.tintColor = [UIColor whiteColor]; 用于顶部的其他自定义按钮。
Juan Zamora 2013年

6

一种低保真方法可能是将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将其子类化,并将相同的视图置于背景之上,但置于其他所有事物的后面,可能会获得相似的结果,同时又不那么笨拙。


我见过的另一种解决方法是使用alpha UINavigationBar

self.navigationController.navigationBar.alpha = 0.5f;

编辑:实际上,经过测试,似乎这没有提供预期的行为(或任何行为):

.8 alpha

带.8 alpha的导航栏

未经调整的Alpha

在此处输入图片说明

显然,您只想在iOS 7设备上执行此操作。因此,在实现其中任何一个之前,请添加一些版本检查


我第二种方法是更新alpha和tintColor以获得所需的颜色。
StuartM 2013年

如果您能够以这种侵入性较小的方式获得理想的效果,那么就完全可以了。但是我不确定它的效果如何。
凯文

我得到的唯一问题(它似乎没有在您的图片中显示)是将视图直接添加到导航栏的顶部,结果导致控件被阻止:cl.ly / image / 3d3C2o0N283S
SpacePyro

哎呀,现在我明白了。应该是[self.navigationController.view insertSubview:backgroundView belowSubview:self.navigationController.navigationBar];
Kevin

是的,我想这就是你的意思。;)这无疑给了我更好的色彩选择范围。考虑到模糊效果实际上仍然会使其下的任何东西饱和,因此要获得原始颜色的鲜艳度可能是不可能的。我现在只需要使用深色即可。
2013年

4

不要使用RGB格式创建UIColor对象,而应使用HSB并增加饱和度参数。(学分到山姆Soffes谁介绍这种方法在这里

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

注意:此解决方案是一个折衷方案,不适用于具有高饱和度的颜色。

要从设计中选择HSB颜色,可以使用ColorSnapper之类的工具,该工具可让您简单地复制UIColor HSB格式。

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


3

现在,该问题已由Apple在新的7.0.3版本中修复。


1
是的,它们的色彩实现在7.0.3中肯定已更改。现在,只需将饱和度提高约10-15%,即可获得所需的颜色。在我还需要添加额外的图层之前。
Matej Bukovinski

谢谢你让我知道!为此,我将向我的图书馆推送更新。
SpacePyro 2013年

1
并在7.1> _ <中未解决
Leo Natan 2014年

1

我用@ aprato的解决方案,但发现其中来自新的VC的新层(例如,几拐角情况UINavigationItemButtonViewsUINavigationItemViews等等)将被自动地插入到下面的一个位置extraColorLayer(这将导致由受影响的那些标题或按钮元素extraColorLayer,因此颜色比平时更暗)。因此,我调整了@aprato的解决方案,以将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
}

由于图层和子视图没有混合在一起,因此我不需要重载addSubView
Rob van der Veer


0

这些hack都不是必需的:)。只需设置:

self.navigationController.navigationBar.translucent = NO;

对于iOS 7,默认半透明设置为TRUE。


17
但是这个问题也需要半透明。
Leo Natan

:)谢谢,它为我工作。但是,导航栏下方有一个1px黑色的底部边框。有什么办法可以删除它?
Pritesh Desai 2013年

0

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

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];

1
如果您要匹配iOS 7的样式,则在标题文本上使用阴影可能是不合适的。
Nick Locking

没错,在iOS 7中,Apple不再在其导航栏文本上设置阴影。如果您想要自定义外观,则可以选择。
bryguy1300

0

我在尝试在iOS 7上设置透明度禁用的统一导航栏时遇到了此问题。

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

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

三行代码,非常简单,可同时在iOS 6和iOS 7上使用(iOS 6不支持barTintColor)。


0

Simon Booth提供了很棒的Dropin UINavigationController替代品,可从GitHub此处获得 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;

除非我缺少任何内容,否则该库的条形不是半透明的。
里维拉2014年


-1

坦白地说,以上答案可能是正确的,但以下技巧对我很轻松。

// 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.imageRed和的图像self.imageBlack

< 自我形象黑 >黑色图像在此方括号中将不可见,因为它是透明的:)

< self.imageRed>红色图像在此括号中。


这不会使您模糊。
Ortwin Gentz

-1

有没有一种方法可以使用@aprato解决方案而无需将UINavigationBar子类化。

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

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

谢谢


您难道不可以将with 包裹在UIViewController里面吗?也可以将其作为一个单独的问题更好地回答,而不是在此处发布。UINavigationController[[[UINavigationController alloc] initWithRootViewController:<YourViewController>]
SpacePyro

-2

一种获得所需颜色的简单方法是使用

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

只要您的图像具有一定的Alpha,就可以使用半透明效果,您可以通过更改图像来设置Alpha。这是刚刚在iOS7中添加的。垂直图像的宽度和高度为640x88像素(如果要在状态栏下方,则在88像素上增加20像素)。


但是,这不会保留模糊。有透明度,但没有模糊。
Leo Natan
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.