动态修改NavigationBar的颜色

作者: Aeron_Xie | 来源:发表于2016-01-04 17:53 被阅读7238次

如果我们想动态的修改NavigationBar的颜色会肿么做呢?

首先我们想到的肯定是在UISrollView的delegate方法

- (void)scrollViewDidScroll:(UIScrollView *)scrollView

根据当前的contentOffset更新navigationBar的backgroundColor即可.

思路

首先想到的是最常用的[UINavigationBar appearance],我们一般会在AppDelegate中使用它对navigationBar进行统一的设置。但是如果试一下,会发现在scrollViewDidScrollView中调用它并不能动态地改变navigationBar的颜色,原因是: iOS应用出现变化时,视图会进入一个窗口,它不能改变已经再一个窗口的外观。

我们换一个方法试试看,直接修改UINavigationBar的backgroudColor:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
UIColor *color = [UIColor redColor];
CGFloat offsetY = scrollView.contentOffset.y;
if (offsetY > 0) {
    CGFloat alpha = 1 - ((64 - offsetY) / 64);
    self.navigationController.navigationBar.backgroundColor = [color colorWithAlphaComponent:alpha];
} else {
     self.navigationController.navigationBar.backgroundColor = [color colorWithAlphaComponent:0];
     }
}

然后发现,怎么是。。。。。有一半咋没有颜色 ????这是神马情况???

通过reveal查看其中的层级结构,发现NavigationBar上面有一个_UINavigationBarBackground的遮盖,正是它决定了navigationBar的背景色。

那我们把这个view拿到,删除不就可以了么?继续尝试。

我们通过打印 self.navigationController.navigationBar.subviews看到navigationBar上有两个子控件。

"<_UINavigationBarBackground: 0x7fed90f43990; frame = (0 -20; 414 64); opaque = NO; autoresize = W;                     userInteractionEnabled = NO; layer = <CALayer: 0x7fed90f36a90>>",
"<_UINavigationBarBackIndicatorView: 0x7fed90d053f0; frame = (0 11.6667; 13 21); alpha = 0; opaque = NO;             userInteractionEnabled = NO; layer = <CALayer: 0x7fed90dc6e50>>"

我们可以通过遍历把 _UINavigationBarBackground 拿到并删除即可

for (UIView *view in self.navigationController.navigationBar.subviews) {
    if ([view isKindOfClass:NSClassFromString(@"_UINavigationBarBackground")]) {
        [view removeFromSuperview];
    }
}

然后发现这样就可以了,不过状态栏还是白色的啊~~~

这时我们改变下状态栏的颜色就好了,要修改状态栏的颜色比较麻烦,那我们可以直接在navigationBar上加上一层遮罩就好

UIView *overlay = [[UIView alloc] initWithFrame:CGRectMake(0, -20, [UIScreen mainScreen].bounds.size.width,20)];
overlay.backgroundColor = [UIColor redColor];
[self.navigationController.navigationBar insertSubview:overlay atIndex:0];

不过这么干的话,那就要修改两个控件颜色。。。。这样修改起来非常的麻烦,有没有什么好点的方法呢????

换一个思路

考虑到继承UINavigationBar使用起来会非常不便,我们决定用Category来实现,首先定义我们的category:

@interface UINavigationBar (BackgroundColor)
- (void)lt_setBackgroundColor:(UIColor *)backgroundColor;
@end

我们可以使用associatedObject将overlay动态地绑定到UINavigationBar的instance上,当调用lt_setBackgroundColor的时候,我们只要更新这个overlay就可以了

   static char overlayKey;
@implementation UINavigationBar (BackgroundColor)


- (UIView *)overlay
{    return objc_getAssociatedObject(self, &overlayKey);
}

- (void)setOverlay:(UIView *)overlay
{
objc_setAssociatedObject(self, &overlayKey, overlay, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (void)lt_setBackgroundColor:(UIColor *)backgroundColor
{    
    if (!self.overlay) {
    [self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
    [self setShadowImage:[UIImage new]];             
    self.overlay = [[UIView alloc] initWithFrame:CGRectMake(0, -20, [UIScreen mainScreen].bounds.size.width, 64)];
    [self insertSubview:self.overlay atIndex:0];  
}   
     self.overlay.backgroundColor = backgroundColor;
}
@end

最后在scrollViewDidScroll中,我们就可以动态地修改UINavigationBar的backgroundColor了:

[self.navigationController.navigationBar lt_setBackgroundColor:[color colorWithAlphaComponent:alpha]];

这个方法是参考了 LTNavigationBar 第三方类库,这类库已经给我们封装好了这些方法,使用起来非常简单

详情请点这里

相关文章

网友评论

  • seanward:遍历_UINavigationBarBackground 不行,因为在iOS11上就不是这样的subviews了
    seanward:@jasonFlora 我直接自己写了一个view做nvabar,这个库不适合我的需求
    a60590dc79c3:看了一下作者的github,已经修改了,适配了ios11系统和xcode 9
    a60590dc79c3:那么阁下是怎么解决的呢?我这个之前用了这个方法,现在用xcode9之后,失效了,现在应该如何解决呢
  • NSblacker:后一种方法确实可以,后来和其他页面出了矛盾。想到的办法是:NavigationBar可以设置backgroundImage,所以函数画一个纯色的图片即可:
    + (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;
    }
  • 4d16197b657b:我之前一直没想明白改变前一个页面导航透明度影响的后一个页面的导航这个问题 你这个demo解决了我的问题 谢谢
  • 长岛冰泪Willin:跟一个旧识同名
  • 花前月下:还有一种思路就是 用kvo 来监听变化

本文标题:动态修改NavigationBar的颜色

本文链接:https://www.haomeiwen.com/subject/bilahttx.html