UINavigationBar,只要是做iOS开发的肯定都碰到过。今天趁着手头的没有砖可搬,好好整理一下。
层级关系
首先写一个简单的UINavigationController,查看视图层级。可以看到下面的层级关系。
第一级 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];
那么恭喜你掉坑里了,如何正确设置。以及为什么要这么设置我们下面一一道来。
突变的层级结构
当我们设置了背景图片,卧槽。第三和第四级的那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;
}
只要了解了层次结构,大部分的问题都迎刃而解。如果童鞋们,还有什么问题,可以留言,我以后跟新补充。