最近理了一下UINavigationBar,发现UINavigationController使用的时候有很多问题。所以结合自己使用的理解,总结一下。
UINavigationController 用来管理 UIViewController(视图控制器),它以栈的形式管理,UIViewController个数理论上不受限制(当然内存还是要考虑的),push和pop方法来弹入弹出UIViewController。虽然UINavigationController是UIViewController的子类,但是UINavigationController是不能被push方法打开的。只能被UINavigationController 父类函数presentViewController:弹出。
初始化函数说明 UINavigationController 最少有一个UIViewController 在底部。
- (instancetype)initWithRootViewController:(UIViewController *)rootViewController; // Convenience method pushes the root view controller without animation.
UINavigationController常用push 函数来打开一个UIViewController
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
UINavigationController 还支持一次性打开多个UIViewController (底控制器->(VC1 、VC2 、VC3)) ,但是最后一个UIViewController在最上面。业务场景很少用这个函数。
- (void)setViewControllers:(NSArray<UIViewController *> *)viewControllers animated:(BOOL)animated;
关闭当前控制器
- (nullable UIViewController *)popViewControllerAnimated:(BOOL)animated;
关闭多个视图控制器
- (nullable NSArray<__kindof UIViewController *> *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated;
关于关闭多个控制器实际场景中会出现 ,关闭到指定的UIViewController。可以使用
@property(nonatomic,copy) NSArray<__kindof UIViewController *> *viewControllers;
先获取所有打开过的UIViewController,然后找到目标UIViewController,然后使用函数popToViewController,就可以关闭到指定的界面。(当然关闭的这个界面必须是在 viewControllers 中的)
-(void)popToViewController:(Class)vcClass animated:(BOOL)animated{
UINavigationController * navigationC = self.navigationController;
if (navigationC){
for (UIViewController *tempVC in navigationC.viewControllers) {
if ([tempVC isKindOfClass:vcClass]) {
[navigationC popToViewController:tempVC animated:animated];
break;
}
}
}
}
如果要关闭的UIViewController 没有在当前 UINavigationController怎么办呢?当然有办法的,UINavigationController是不能被push 的,所以我们可以查看 presentedViewController 属性,一层一层的查找到你所需要的关闭的UIViewController。
我们大多数App主界面样式UITabBarController 。但是和UINavigationController不同的配合会产生不同的交互效果,当然这也关系到 UINavigationController 的使用。
UITabBarController *tabBarVC = [[UITabBarController alloc] init];
UIViewController *firstVC = [[UIViewController alloc] init];
firstVC.tabBarItem.title = @"首页";
UIViewController *secondVC = [[UIViewController alloc] init];
secondVC.tabBarItem.title = @"我的";
tabBarVC.viewControllers = @[firstVC,secondVC];
UINavigationController * navigationVC = [[UINavigationController alloc] initWithRootViewController:tabBarVC];
self.window.rootViewController = navigationVC;
UITabBarController *tabBarVC = [[UITabBarController alloc] init];
UIViewController *firstVC = [[UIViewController alloc] init];
UINavigationController * firstNavigationVC = [[UINavigationController alloc] initWithRootViewController:firstVC];
firstNavigationVC.tabBarItem.title = @"首页";
UIViewController *secondVC = [[UIViewController alloc] init];
UINavigationController * secondNavigationVC = [[UINavigationController alloc] initWithRootViewController:secondVC];
secondNavigationVC.tabBarItem.title = @"我的";
tabBarVC.viewControllers = @[firstNavigationVC,secondNavigationVC];
self.window.rootViewController = tabBarVC;
有兴趣大家可以做一个dome 或者直接看一下我推荐的App 看一下就能够明白。大家可以根据实际场景来选择代码实现方式。
当我们根据实用场景选择 3 的一种方式后,接下来给我们带来的问题就是 navigationItem的设置问题。
这种方式设置navigationItem 的时候由于 UINavigationController的根视图(rootViewController)是 UITabBarController,所以设置 navigationItem 的时候是根据UITabBarController的属性selectedIndex来更换设置其navigationItem。我们利用这种方式来实现切换底部tabbar,头部的navigationItem 变化的效果。
这种方式设置navigationItem 的时候 UITabBarController 中包含 UINavigationController,UINavigationController的根视图(rootViewController)是其tabbar 切换的不同UIViewController。所以直接在UIViewController设置navigationItem即可。
这一部分强烈建议大家去做一个dome 加深一下印象。
//应用中所有navigationBar 修改默认配置
[UINavigationBar appearance].translucent = YES;
[[UINavigationBar appearance] setTintColor:[UIColor blackColor]];
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"clearbg.png"] forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setShadowImage:[UIImage imageNamed:@"clearbg.png"]];
[[UINavigationBar appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor blackColor]}];//设置title颜色
//返回按钮设置
[UINavigationBar appearance].backIndicatorImage = [UIImage imageNamed:@"Titlebackbg.png"];
[UINavigationBar appearance].backIndicatorTransitionMaskImage = [UIImage imageNamed:@"Titlebackbg.png"];
//设置按钮颜色
[[UIBarButtonItem appearanceWhenContainedInInstancesOfClasses:@[[UISearchBar class]]] setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor blackColor],NSFontAttributeName:[UIFont systemFontOfSize:14.0]} forState:UIControlStateNormal];
[[UIBarButtonItem appearance] setTitleTextAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:14.0f],NSForegroundColorAttributeName: [UIColor redColor]} forState:UIControlStateNormal];
[[UIBarButtonItem appearance] setTitleTextAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:14.0f],NSForegroundColorAttributeName: [UIColor blackColor]} forState:UIControlStateHighlighted];
[[UIBarButtonItem appearance] setTitleTextAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:14.0f],NSForegroundColorAttributeName: [UIColor colorWithWhite:0 alpha:0.5]} forState:UIControlStateDisabled];
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStyleDone target:nil action:nil];
最好的方式是利用runtime 在 UIViewController 的 viewDidLoad函数中实现以上代码。
代码传送门