多控制器管理


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)

多控制器管理_第1张图片
Segue.png

Segue的属性

/** 唯一标识 */
@property (nullable, nonatomic, copy, readonly) NSString *identifier;

/** 来源控制器 */
@property (nonatomic, readonly) __kindof UIViewController *sourceViewController;

/** 目标控制器 */
@property (nonatomic, readonly) __kindof UIViewController *destinationViewController;
多控制器管理_第2张图片
identifier.png
多控制器管理_第3张图片
从来源控制器跳转到目标控制器.png

Segue的类型

自动类型
  • 按着Control键,直接从控件拖线到目标控制器
多控制器管理_第4张图片
自动类型的Segue.png
  • 点击某个控件后(比如按钮),自动执行Segue,自动完成界面跳转
  • 一般用于点击某个控件后,不需要做任何判断,一定要跳转到下一个界面。建议使用“自动类型的Segue”
手动类型
  • 需要通过写代码手动执行Segue,才能完成界面跳转
  • 一般用于点击某个控件后,需要做一些判断才能跳转的情况下,建议使用“手动类型的Segue”
  • 手动类型的Segue需要设置一个标识
  • 按住Control键,从来源控制器拖线到目标控制器
多控制器管理_第5张图片
手动类型的Segue设置方法.png
  • 在恰当的时刻,使用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的-(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:
多控制器管理_第6张图片
控制器的声明周期.png

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;
}

你可能感兴趣的:(多控制器管理)