IOS 10.x系统 设置导航栏背景颜色,上面有层蒙板

今天用Xcode8.2 新建一个Demo,底部一个Tabbar,上面一个导航栏,之前的项目是老板版建立的,将之前的代码拉进来,瞬间方了,肿么回事!看到下效果图

A)[UINavigationBar appearance].backgroundColor = RColor;
这里写图片描述

B)修改后的效果
这里写图片描述

可以看出颜色的不同,后者颜色深些,这才是该颜色值,我们利用Xcode–Debug–View Debugging–Caputre View Hierarchy,看视图的层级关系
这里写图片描述

A)
这里写图片描述

原来NavagationBar前有好几层的view,是他们遮挡了真正的颜色,打印看NavigationBar的subviews

  NSLog(@"navigationbar subviews recursive description:\n\n%@\n\n",[self.navigationController.navigationBar performSelector:@selector(recursiveDescription)]);

这里写图片描述

最前面的一层 颜色有透明度

B)
这里写图片描述

此处的解决方法是,在程序运行时,插入一个view在NavigationBar中,在B的层级图中可以UIView。

贴上代码

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

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

- (void)YCFSetBackgroundColor:(UIColor *)backgroundColor{
    if (!self.overlay) {
        [self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];

        UIView *backgroundView = [self KPGetBackgroundView];
        self.overlay = [[UIView alloc] initWithFrame:backgroundView.bounds];
        self.overlay.userInteractionEnabled = NO;
        self.overlay.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;

        [backgroundView insertSubview:self.overlay atIndex:0];
    }
    self.overlay.backgroundColor = backgroundColor;
}

- (void)YCFSetBackgroundImage:(UIImage *)imageName{

    if (!self.overlay) {
        [self setBackgroundImage:imageName forBarMetrics:UIBarMetricsDefault];

        UIView *backgroundView = [self KPGetBackgroundView];
        self.overlay = [[UIView alloc] initWithFrame:backgroundView.bounds];
        self.overlay.userInteractionEnabled = NO;
        self.overlay.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;

        [backgroundView insertSubview:self.overlay atIndex:0];
    }
    self.overlay.backgroundColor = [UIColor clearColor];
}


- (UIView*)KPGetBackgroundView{
    //iOS10之前为 _UINavigationBarBackground, iOS10为 _UIBarBackground
    //_UINavigationBarBackground实际为UIImageView子类,而_UIBarBackground是UIView子类
    //之前setBackgroundImage直接赋值给_UINavigationBarBackground,现在则是设置后为_UIBarBackground增加一个UIImageView子控件方式去呈现图片

    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0) {
        UIView *_UIBackground;
        NSString *targetName = @"_UIBarBackground";
        Class _UIBarBackgroundClass = NSClassFromString(targetName);

        for (UIView *subview in self.subviews) {
            if ([subview isKindOfClass:_UIBarBackgroundClass.class]) {
                _UIBackground = subview;
                break;
            }
        }
        return _UIBackground;
    }
    else {
        UIView *_UINavigationBarBackground;
        NSString *targetName = @"_UINavigationBarBackground";
        Class _UINavigationBarBackgroundClass = NSClassFromString(targetName);

        for (UIView *subview in self.subviews) {
            if ([subview isKindOfClass:_UINavigationBarBackgroundClass.class]) {
                _UINavigationBarBackground = subview;
                break;
            }
        }
        return _UINavigationBarBackground;
    }
}

#pragma mark - shadow view

- (void)KPHideShadowImageOrNot:(BOOL)bHidden{
    UIView *bgView = [self KPGetBackgroundView];

    //shadowImage应该是只占一个像素,即1.0/scale
    for (UIView *subview in bgView.subviews) {
        if (CGRectGetHeight(subview.bounds) <= 1.0) {
            subview.hidden = bHidden;
        }
    }
}

参考链接1
参考链接2

上面两种方法都是可行。
上面是因为设置translucent是YES,7.0以后,默认值是YES,以前都是NO,事实上都是这个属性在搞鬼

New behavior on iOS 7.
 Default is YES.
 You may force an opaque background by setting the property to NO.
 If the navigation bar has a custom background image, the default is inferred 
 from the alpha values of the image—YES if it has any pixel with alpha < 1.0
 If you send setTranslucent:YES to a bar with an opaque custom background image
 it will apply a system opacity less than 1.0 to the image.
 If you send setTranslucent:NO to a bar with a translucent custom background image
 it will provide an opaque background for the image using the bar's barTintColor if defined, or black
 for UIBarStyleBlack or white for UIBarStyleDefault if barTintColor is nil.

YES(半透明),NO(不透明)
如果自定义的图像alpha<1.0,translucent=NO,则导航栏会为图像提供不透明背景,
如果自定义的图像alpha<1.0,translucent=YES,则导航栏会为图像提供透明背景

根据测试,其实设置backgroundcolor跟设置backgroundImage是一样的效果

若是在最开始就设置了translucent=NO,那么后续代码也就不需要,也不会出现半透明的导航栏。正好这个机会也好好了解了NavigationBar的视图层次,不然也不晓得它是如何实现的。

有个疑问,在运行时给NavigationBar插入一个UIView之后,原先的那个UIVisualEffectView不见了,这是怎么回事呢?知道的请告知。谢谢!

如果有什么不对的地方也请指正,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值