首页 文章

为iOS 7半透明UINavigationBar实现明亮鲜艳的色彩

提问于
浏览
172

iOS 7.1 UPDATE :在此更新中,似乎忽略了修改UINavigationBar中Alpha通道的变通方法 . 现在,最好的解决方案似乎只是'deal with it'并希望您选择的任何颜色都可以呈现半透明效果 . 我仍然在寻找解决这个问题的方法 .


iOS 7.0.3 UPDATE :使用iOS 7.0.3时,GitHub library we created已更新为略有解决此问题 . 不幸的是,没有神奇的公式可以支持iOS 7.0.2及更早版本和iOS 7.0.3中创建的颜色 . 似乎Apple改善了饱和度,但是以不透明度为代价(因为模糊的半透明度取决于不透明度水平) . 我和其他一些人正在努力为此创建更好的解决方案 .


我相信很多人已经遇到过这样的问题:iOS 7倾向于使半透明的UINavigationBar的颜色饱和 .

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

UINavigationBar, Opaque

然而,有了半透明,我得到了这个 . 背景视图是白色的,据我所知会使这个视图更轻一些:

UINavigationBar, Translucent

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

Facebook UINavigationBar, Translucent

..所以我知道必须有某种方式 . 背景视图在这里显然有所不同,但其大部分内容也是灰色/白色 . 似乎无论你放入什么样的色调,你都无法在半透明的情况下获得鲜艳的色彩 .

Updated with solution.

这是我最终提出的解决方案 . 我拿了aprato的解决方案,然后在 UINavigationController 子类中包含了自定义 UINavigationBar . 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 回答

  • 1

    这些黑客都不是必需的:) . 只需设置:

    self.navigationController.navigationBar.translucent = NO;
    

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

  • 6

    iOS 7.0.3 UPDATE: 如上所述,7.0.3改变了一切 . 我更新了我的要点 . 希望这会随着人们的升级而消失 .

    Original Answer: 我结束了其他两个答案的黑客攻击 . 我正在对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);
      }
    
  • 0

    在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)
    
  • 4

    我没有提出这个解决方案,但似乎工作得相当好 . 我刚刚将它添加到我的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

    一种低保真方式可能会固定一个 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背后

    enter image description here

    (将颜色从较低的示例更改为强调透明度 . 移动时透明度/模糊更明显 . )

    UINavigationBar 进行子类化并将相同的视图置于背景之上但落后于其他所有内容可能会获得类似的结果,同时不那么黑客 .


    我见过的另一个解决方案是使用UINavigationBar的alpha:
    self.navigationController.navigationBar.alpha = 0.5f;
    编辑:实际上,在测试后,它似乎没有提供打算行为(或任何行为):

    .8 alpha

    Navigation bar with .8 alpha

    未经调整的alpha

    enter image description here

    显然,您只想在iOS 7设备上执行此操作 . 所以,在实施其中任何一个之前add some version check .

  • 0

    不要使用RGB格式创建UIColor对象,而是使用HSB并增加饱和度参数 . (对Sam Soffes描述此方法的信用here

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

    注意:此解决方案是一种折衷方案,对于具有高饱和度的颜色效果不佳 .

    要从您的设计中选择HSB颜色,您可以使用像ColorSnapper这样的工具,它允许您简单地复制UIColor HSB格式 .

    您也可以尝试UIColor类别(GitHub Link)从David Keegan修改现有颜色 .

  • 10

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

  • -1

    我使用了@ aprato的解决方案但发现了一些极端情况,其中来自新VC的新层(例如 UINavigationItemButtonViewsUINavigationItemViews 等)将自动插入到 extraColorLayer 下方的位置(这会导致这些 Headers 或按钮元素受到影响 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
    }
    
  • 0

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

    通过我的修改,屏幕上的结果颜色(在白色背景上选取)将与传递到 setBarTintColor 的值完全相同 . 我认为这是一个了不起的解决方案 .

  • 9

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

    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上设置透明度为DISABLED的均匀彩色导航栏时,我遇到了这个Q / A.

    在使用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) .

  • 52

    这是一个伟大的Dropin UINavigationController更换,可从Simon Booth获得,可在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;
    
  • 0

    作为@bernhard mentioned above,可以使条纹色调饱和,以获得所需的导航栏外观 .

    我为这种调整写了一个BarTintColorOptimizer utility . 它优化了半透明条纹色调,使条形图的实际颜色与iOS 7.x及更高版本中所需的颜色相匹配 . 有关详细信息,请查看this answer .

  • 3

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

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

    红色图片在此括号中 .

  • -2

    有没有办法使用@aprato解决方案而无需子类化UINavigationBar .

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

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

    谢谢

  • 0

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

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

    只要您的图像具有一些alpha,半透明就可以工作,您可以通过更改图像来设置alpha . 这只是在iOS7中添加的 . 垂直方向的图像宽度和高度为640x88px(如果您希望它位于状态栏下方,则将其添加到88) .

相关问题