UINavigationBar组成
UINavigationBar 可以说是使用率比较高的控件了,在UINavigationController 中包含着它,查阅苹果官方文档可以看到UINavigationBar 上可以显示的内容,如图:
图1
左侧的 backItem Title,中间的 topItem Title,右侧topItem rightBarButtonItem,在顶部上方还有 topItem prompt,用单行来做解释说明。
UINavigationBar结构
在了解一个控制的基础结构时候,可以利用 Xcode 的 View UI Hierarchy 工具方便查看控件内部的结构组成,如图:
图2
在测试 Demo 上可以看到,在设置了 topItem Title, rightBarButtonItem 和 topItem prompt 后,UINavigationBar 的结构如上图所示,我们可以只关注 UINavigationBar部分,它继承于UIView,属于 UINavigationController,在其内部有三部分,分别是 UIBarBackground,UINavigationBarContentVIew,UINavigationBarModernPromptView。接下来我分别用不同的颜色来区分各个视图的含义。
UIBarBackground
当将一个视图控制器 push 入栈后,在这个控制器的 - (void)viewDidLoad 方法中运行如下代码:
self.view.backgroundColor = [UIColor orangeColor];
self.navigationController.navigationBar.backgroundColor = [UIColor greenColor];
self.navigationController.navigationBar.barTintColor = [UIColor orangeColor];
图3
分别点击视图层级对照右侧显示效果可以看到,我们设置的navigationBar.backgroundColor 其实是 UINavigationBar; UIBarBackgroundShadowContentImageView 是导航栏底部分分割线; 而我们设置导航栏的橙色区域缺显示在UIVisualEffectSubview中; UINavationBarContentView 是我们自定义的返回按钮存放的区域。
半透明设置
在运行模拟器的时候,发现同样是设置了相同的颜色,为什么导航栏的颜色比控制器视图的颜色浅一点呢?如图:
官方给出的设置是 translucent 属性设置,再添加一行代码后运行看下效果:
self.navigationController.navigationBar.translucent =NO;
图5
我们发现UIVisualEffectView视图没了,而是一个ImageView代替了,并且在UIBarBackgroundShadowView上,没有在UIBarbackground视图上。 对照后才知道,半透明的效果原来是UIVisualEffectView的遮挡的效果。 当注释掉下面一行代码运行后
self.navigationController.navigationBar.barTintColor = [UIColor orangeColor];
图6
少了 UIVisualEffectSubview 两个视图,但是还有半透明效果,可以看到底层的绿色,因为模式 barStyle 是白色的,translucent 模式是 YES。如果要设置导航栏背景图又会是怎样的效果呢?我们运行一下代码再观察:
图7
此时和 translucent = NO 的效果一样,用一个imageView代替了UIVisualEffectView,位置也一样。还分别尝试了 translucent = YES,和 barTintColor 设置颜色的时候,效果还是一样。
还有一些变化要说明:
- 在设置了 translucent = NO,的时候,坐标原点的位置是从导航栏左下角开始计算。
- 设置 prompt 属性后,导航栏的高度发生了变化,多了30pt。
- 在自定义返回按钮后,侧滑的手势失效。网上有解决方案,主要代码如下:
//自定义左侧返回按钮后,侧滑无效问题修改
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (self.navigationController.childViewControllers.count > 1) {
self.gestureDelegate = self.navigationController.interactivePopGestureRecognizer.delegate;
self.navigationController.interactivePopGestureRecognizer.delegate = self;
}
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
self.navigationController.interactivePopGestureRecognizer.delegate = self.gestureDelegate;
}
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
return self.navigationController.childViewControllers.count > 1;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return self.navigationController.childViewControllers.count > 1;
}
UINavigationBarContentView
我们在设置导航栏上的item时候,都是添加到这个UINavigationBarContentView上面的。例如自定义返回按钮
UIButton *leftButton = [UIButton buttonWithType:UIButtonTypeCustom];
[leftButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[leftButton setTitle:@"goBackBtn" forState:UIControlStateNormal];
[leftButton addTarget:self action:@selector(goBack) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *leftButtonItem = [[UIBarButtonItem alloc]initWithCustomView:leftButton];
self.navigationItem.leftBarButtonItem = leftButtonItem;
- (void)goBack {
[self.navigationController popViewControllerAnimated:YES];
}