title : 多控制器管理
category : UI
多控制器管理、UINavigationController、UITabBarController
标签(空格分隔): IOS
[TOC]
UINavigationController
UINavigationController的使用步骤
- 1 初始化UINavigationController
- 2 设置UIWindow的rootViewController为UINavigationController
- 3 根据情况,通过push方式添加对应个数的子控制器
控制器入栈
// 创建导航控制器
UINavigationController *nav = [[UINavigationController alloc] init];
// 将控制器testViewController添加到导航控制器nav中
[nav pushViewController:testViewController animated:YES];
// 只要当前控制器是导航控制器的子控制器,就可以通过该属性直接获取到当前控制器所在的导航控制器
self.navigationController
- 初始化的时候创建添加子控制器
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:childViewController];
- 获取导航控制器的栈顶控制器
nav.topViewController
控制器出栈
- 弹出顶部控制器
[nav popViewControllerAnimated:YES];
- 跳转到跟控制器
[nav popToRootViewControllerAnimated:YES];
其他导航条的属性
- 一个导航控制器只有一个导航条,也就是说所有的子控制器共用一个导航条
- 导航条上显示的内容和栈顶控制器有关,所以,导航条上显示什么内容由栈顶控制器控制
注意
导航条左边返回
按钮的文字是由上一个控制器决定的
导航条的基本设置
// 控制当前控制器对应的导航条显示的内容
self.navigationItem.title = @"标题";
// 给导航条添加一个自定义视图
self.navigationItem.titleView = [[UIView alloc] init];
// 导航条的左边添加按钮
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"左边按钮" style:UIBarButtonItemStylePlain target:nil action:nil];
// 导航条的右边添加按钮
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"右边按钮" style:UIBarButtonItemStylePlain target:nil action:nil];
// 设置返回按钮的显示
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:nil action:nil];
导航控制器中控制器的结构
-
IOS7.0以后
:导航控制器中子控制器的view是全屏化的。也就是从状态栏顶部到控制器底部 -
IOS7.0之前
:导航控制器中子控制器的view不是全屏化的。它的view是从导航条下面开始的(也就是Y=64)。
导航控制器管理子控制器的原理
- 导航控制器是通过栈的形式来管理它的子控制器(也就是先进后出)
- 导航条的高度是44(最上面的20不属于导航条,它属于系统的状态栏)
- 导航控制器的高度是从状态栏的最顶部开始的,导航控制器和状态栏覆盖在导航控制器上面。
- 当将新的控制器添加到导航控制器中的时候,新的控制器的view会添加到当前控制器中。而旧的控制器的view会被暂时放到缓存池中。但不会被销毁
- 当将控制器移除的时候,被移除的控制会被销毁。
Segue
什么是Segue
storyBoard上每一根用来界面跳转的线,都是一个UIStoryBoardSegue对象(简称Segue)
Segue的属性
/** 唯一标识 */
@property (nullable, nonatomic, copy, readonly) NSString *identifier;
/** 来源控制器 */
@property (nonatomic, readonly) __kindof UIViewController *sourceViewController;
/** 目标控制器 */
@property (nonatomic, readonly) __kindof UIViewController *destinationViewController;
Segue的类型
自动类型
- 按着Control键,直接从控件拖线到目标控制器
- 点击某个控件后(比如按钮),自动执行Segue,自动完成界面跳转
- 一般用于点击某个控件后,不需要做任何判断,一定要跳转到下一个界面。建议使用“自动类型的Segue”
手动类型
- 需要通过写代码手动执行Segue,才能完成界面跳转
- 一般用于点击某个控件后,需要做一些判断才能跳转的情况下,建议使用“手动类型的Segue”
- 手动类型的Segue需要设置一个标识
- 按住Control键,从来源控制器拖线到目标控制器
- 在恰当的时刻,使用perform方法执行对应的Segue
// Segue必须由来源控制器来执行,也就是说,这个perform方法必须有来源控制器来调用
[self performSegueWithIdentifier:@"login2contacts" sender:nil];
Segue跳转传值的内部原理
eg:
[self performSegueWithIdentifier:@"login2contacts" sender:nil];
-
performSegueWithIdentifier: sender:
方法的完整执行过程- 这个self是指来源控制器
- 根据identifier去storyBoard中找到对应的线,新建UIStoryboardSegue对象
- 设置Segue对象的sourceViewController(来源控制器)
- 新建并设置Segue对象的destinationViewController(目标控制器)
-
在调用Segue跳转方法(执行Segue的
- (void)perform
方法)之前会执行- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
方法。在该方法中会将performSegueWithIdentifier: sender:
方法中创建好的Segue传递进来。- 在这个Segue中,可以获取Segue的
sourceViewController
(来源控制器)和destinationViewController
(目标控制器)和Segue的identifier
,然后再执行跳转,可以在这里进行数据的传递。
- 在这个Segue中,可以获取Segue的
其中Segue的
-(void)perform
方法内部相当于以下实现
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// 获取来源控制器
UIViewController *sourceVc = segue.sourceViewController;
// 拿到来源控制器的导航控制器
UINavigationController *nav = sourceVc.navigationController;
// 从来源控制器跳转到目标控制器
[nav pushViewController:segue.destinationViewController animated:YES];
}
数据的传递
数据的顺传
- 将来源控制器中的数据传递到目标控制器
- 通过执行
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
方法,将来源控制器的数据传递到目标控制器
- 通过执行
数据的逆传
数据的逆传可以使用代理
或通知
两种方式
控制器的声明周期
- 1 viewDidLoad
- 2 viewWillAppear:
- 3 viewDidAppear:
- 4 viewWillDisappear:
- 5 viewDidDisappear:
// 当控制器的view加载完毕就调用
- (void)viewDidLoad {
[super viewDidLoad];
}
// 控制器即将显示的时候调用
- (void)viewWillAppear:(BOOL)animated
{
}
// 控制器完全显示的时候调用
- (void)viewDidAppear:(BOOL)animated
{
}
// 控制器即将消失的时候调用
- (void)viewWillDisappear:(BOOL)animated
{
}
// 控制器完全消失的时候调用
- (void)viewDidDisappear:(BOOL)animated
{
}
对于从一个控制器跳转到另一个控制器时的顺序
1 viewWillDisappear:
2 viewWillAppear:
3 viewDidDisappear:
4 viewDidAppear:
UINavigationController的常见设置
UINavigationBar的设置
- 导航条的设置
// 该方法只在该类进入时调用一次
+ (void)initialize
{
UINavigationBar *navBar = [UINavigationBar appearance];
// 设置导航条的标题颜色
NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
attrs[NSFontAttributeName] = [UIFont systemFontOfSize:15];
attrs[NSForegroundColorAttributeName] = [UIColor whiteColor];
[navBar setTitleTextAttributes:attrs];
// 设置UIBarButtonItem的主题
UIBarButtonItem *barItem = [UIBarButtonItem appearance];
NSMutableDictionary *barItemAttrs = [NSMutableDictionary dictionary];
barItemAttrs[NSFontAttributeName] = [UIFont systemFontOfSize:15];
barItemAttrs[NSForegroundColorAttributeName] = [UIColor whiteColor];
[barItem setTitleTextAttributes:barItemAttrs forState:UIControlStateNormal];
}
- 拦截所有通过push进来的控制器
/**
* 拦截所有的Push方法
*
* @param viewController 目标控制器
* @param animated 是否动画
*/
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
// 当通过UINavigationController来Push到另一个控制器的时候,隐藏底部的tabBar
viewController.hidesBottomBarWhenPushed = YES;
}