iOS --没事撸一撸控件之UINavigationBar

UINavigationBar,只要是做iOS开发的肯定都碰到过。今天趁着手头的没有砖可搬,好好整理一下。

层级关系

首先写一个简单的UINavigationController,查看视图层级。可以看到下面的层级关系。

iOS --没事撸一撸控件之UINavigationBar_第1张图片
F0629251-5F4D-4347-A585-F8B6C7BD390F.png

第一级 UINavigationBar

这没什么好说的,今天的主角。

第二级

_UINavigationBarBackground(UIImageView)

这个对应了bar 的背景图片方法,不过这个属性不属于共有API

- (void)setBackgroundImage:(nullable UIImage *)backgroundImage forBarPosition:(UIBarPosition)barPosition barMetrics:(UIBarMetrics)barMetrics NS_AVAILABLE_IOS(7_0) UI_APPEARANCE_SELECTOR;

UINavigationButton

这个就是我们自定义的btn

_UINaigationBarBackIndicatorView

这个就是返回按钮,可以自定义图片

@property(nullable,nonatomic,strong) UIImage *backIndicatorImage NS_AVAILABLE_IOS(7_0) UI_APPEARANCE_SELECTOR __TVOS_PROHIBITED;

第三级 第四级----

这边我们主要来看下系统的_UINavigationBarBackground 下面的层级,
首先,我们看到在第三级别里面有个UIImageView.这个imageview 其实是bar下面的深灰色一条线。
我记得我一个基友,来问我这个问题,说要把下面这条线隐藏。我费了老大的力气,才找到这个私有属性名。看下面代码! 就是这个 _shadowView

 UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[ViewController new]];
    NSArray *arry = [nav.navigationBar subviews];
    for (UIView *view in arry) {
        NSString *viewName = NSStringFromClass([view class]);
        if ([viewName isEqualToString:@"_UINavigationBarBackground"]) {
            UIImageView *line = [view valueForKey:@"_shadowView"];
            line.hidden = YES;
        }
    }
    self.window.rootViewController = nav;

毕竟私有属性,比较好的方法就是用别的view盖住他。但直接使用这个属性隐藏,好像基友的应用也是ok的。

话题有点偏了,我们继续回到正题上。
还有一个_UIBackDropView 和_UIBackdropEffectView
这个其实就是系统加的毛玻璃效果。

我们肯定遇到要设置NavigationBar 背景颜色的时候
如果想平常的空间一样

self.navigationController.navigationBar.backgroundColor = [UIColor blackColor];

那么恭喜你掉坑里了,如何正确设置。以及为什么要这么设置我们下面一一道来。

突变的层级结构

CA7AC3B0-E41E-4D4B-A3D0-32E72777BDD8.png

当我们设置了背景图片,卧槽。第三和第四级的那2个view呢。系统在你设置背景图片的时候自定将有毛玻璃效果的2个层级,从视图上移除。让我们可以清楚的看到背景。
但你设置背景颜色时候,那2个层级还在。不知道苹果baba 是怎么想的。

[self.navigationController.navigationBar setBackgroundImage:[UIImage new]forBarMetrics:UIBarMetricsDefault];
    self.navigationController.navigationBar.backgroundColor = [UIColor redColor];

这样就可以完美的设置背景色了。
其实系统也提供了设置全局bar的方法了

[[UINavigationBar appearance] setBackgroundColor:[UIColor redColor]];

这种也可以成功的bar 的背景色。不过是全局的。

--了解NavigationBar 的层次结构,我们就针对大多数问题 做一个解答。
Q:怎么设置NavigationBar 的背景色
上面已经说过了,就不说啦
Q:我想设置NavigationBar 透明,但我想item不隐藏。
首先我们看下层次结构 ,如果你这样设置

self.navigationController.navigationBar.alpha = NO;

肯定不行,我们知道如果设置背景色,是第二级的_UINavigationBarBackground 来显示的,而UINavationBarButton 和他平级。知道这一点就好做了啊。只要设置_UINavigationBarBackground 的alpha 为0 就可以了。
不过要注意一点,因为苹果没开放这个属性。所以为了安全过过审起见,可以这样设置:

[self.navigationController.navigationBar subViews][0] //这个就是_UINavigationBarBackground 设置透明度就好啦。

Q:我想设置nagationBar 滑动渐变效果
如果我根据滑动的偏移量来设置 _UINavigationBarBackground的透明度。那就掉坑了,还记得3 4层级的毛玻璃效果么,只有当_UINavigationBarBackground 完全透明或者设置背景图片的时候才会隐藏。
这就说明,你滑动的时候毛3 4层级还在,你渐变的效果被3.4 层级覆盖住了。就看不到你想要的效果了。
我们一步一步 来:
首先要去掉3 4 层级 (系统的毛玻璃效果)

[self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
或者
[self.navigationController.navigationBar subViews][0] .alpha = 0;

3 4层级去掉了 渐变效果怎么显示啊!
这时候因为要取消3 4层级 占用了系统自带的设置背景色的view。我们可以自己创建一个view来显示背景色。大体思路就是这样。借用别人的一段代码

static char overlayKey;

- (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.overlay = [[UIView alloc] initWithFrame:CGRectMake(0, -20, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds) + 20)];
        self.overlay.userInteractionEnabled = NO;
        self.overlay.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
        [self insertSubview:self.overlay atIndex:0];
    }
    self.overlay.backgroundColor = backgroundColor;
}

只要了解了层次结构,大部分的问题都迎刃而解。如果童鞋们,还有什么问题,可以留言,我以后跟新补充。

你可能感兴趣的:(iOS --没事撸一撸控件之UINavigationBar)