开放中经常通过设置UINavigationBar的属性自定一个导航条的样式,比如透明度、颜色、是否隐藏。接下来介绍常用的属性本质作用。

看下UINavigationController整体布局

UINavigationController控制器的内部View为UILayoutContainerView,内部有2个中要的子控件UINavigationTransitionViewUINavigationBar

UILayoutContainerView中的子控件UIViewControllerWrapperView用来作为导航控制器的View。下面需要看下UINavigationBar内部的控件。

了解了整体的控件结构后,在看下常用的属性设置UINavigationController内部是怎么实现的

默认情况下,UIVisualEffectSubView半透明白色样式,在滚动TableView就有穿透效果。

透明度可以通过NavigationBar的translucent属性设置,默认为YES。修改后为NO,在看下NavigationBar的层级结构。

导航条的UIBarBackground内部UIVisualEffectView移除,并且设置UIBarBackground背景色为白色。

如果想修改NavigationBar的颜色,有两种方案。

方案一 设置前景色

1
2
3
4
5
// 局部修改
[self.navigationController.navigationBar setBarTintColor:[UIColor orangeColor]];
// 全局统一设置
UINavigationBar *bar = [UINavigationBar appearanceWhenContainedIn:self, nil];
[bar setBarTintColor:[UIColor orangeColor]];

设置BarTintColor本质是在UIVisualEffectView添加一个BarTintColor颜色的SubView

方案二 设置背景图片

1
2
3
4
5
6
7
// 局部修改
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"NavBar_"] forBarMetrics: UIBarMetricsDefault];
// 全局统一设置
UINavigationBar *bar = [UINavigationBar appearanceWhenContainedIn:self, nil];
// 如果要设置背景图片,必须填UIBarMetricsDefault,默认导航控制器的子控制器的view尺寸会变化。
// 设置导航条背景图片,一定要在导航条显示之前设置
[bar setBackgroundImage:[UIImage imageNamed:@"NavBar_"] forBarMetrics:UIBarMetricsDefault];

设置UINavigationBar背景图片本质删除其内部的子控件UIVisualEffectView,替换为外界传入的背景图片

实现 NavigationBar显示隐藏也有两种方案

方案一 设置一个空的UIImage作为它的背景图

1
2
3
[self.navigationController.navigationBar  setBackgroundImage:[UIImage  new] forBarMetrics:UIBarMetricsDefault];
// 把导航栏上的分隔线用一个没有图片,但又不为空的UIImage给覆盖掉
[self.navigationController.navigationBar setShadowImage:[UIImage new]];

来看下这总实现这是给你错觉隐藏了导航条,其实本质是通过设置空的图片让内部移除UIVisualEffectView,这种的好处不会影响到导航条内部的UIBarButtonItem。

方案二 设置NavigationBar的Hidden属性

1
[self.navigationController setNavigationBarHidden:YES animated:YES];

开发中遇到的坑

如果自定义导航控制器全局设置导航条的颜色,如果是通过设置背景图片的方式,会出现push的控制器View在导航栏下。

这中需要解决办法是自定义导航控制器通过UIStoryboard加载的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame: [UIScreen mainScreen].bounds];

// UIStoryboard加载导航控制器
ViewController *rootVc = [[ViewController alloc] init];

JJBaseNavigationController *na = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateInitialViewController];

[na pushViewController:rootVc animated:NO];
self.window.rootViewController = na;
[self.window makeKeyAndVisible];

return YES;
}

建议如果全局设置导航条的背景色还是使用上述BarTintColor的方式,避免这种问题。