UINavigationController

Gboy 2019-03-07 10:24:03 863
本文来自 雪山飞狐_91ae ,作者 Gboy

UINavigationController

  • UINavigationController继承自UIViewController,用来展示具有明显的层级结构的内容,让我们更高效的将层级结构的内容展现给用户。在每个层级中用一个UIViewController来展示具体内容。下面的图是iOS设备中的设置界面的图:

iOS设备的设置

UINavigationController是一个容器视图控制器,其内部展示着多个UIViewController的内容。UINavigationController的View由三个部分组成,最上面的UINavigationBar,最下面默认隐藏的toolbar,以及中间部分的UIViewController的View。

UINavigationController的层级结构

UINavigationController的堆栈管理

  • UINavigationController通过其管理的一个UIViewController堆栈来决定中间的View显示什么。中间的View显示的是UIViewController堆栈顶部的UIViewController的View。

UINavigationController
  • 理解上面这幅图很重要。我们看到UINavigationController拥有viewControllers,navigationBar,toolBar这些属性。其中viewControllers是一个数组,在这个数组中以堆栈的形式存放着多个UIViewController。堆栈是先进后出的原则。UINavigationController的中间的View显示的是位于堆栈顶部的UIViewController的View。

  • 位于堆栈最底部的UIViewController我们称之为rootViewController(根视图控制器),一个UINavigationController的UIViewController堆栈中至少有一个视图控制器,也可以说一定存在根视图控制器。我们可以创建一个UIViewController,然后使用系统提供的方法让这个UIViewController进栈,也可以使用系统提供的方法让UIViewController堆栈中的视图控制器出栈。

UINavigationController的创建

创建UINavigationController的方法:

//创建一个视图控制器FirstPageViewController *VC = [[FirstPageViewController alloc] init];//把上面创建的视图控制器作为根视图控制器创建一个UINavigationController//这样UINavigationController的UIViewController堆栈中已经有了一个视图控制器即VC,这时候UINavigationController的中间那部分的View显示的是VC的View。UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:VC];

当我们想要进入这个UINavigationController的页面时可以:
[self presentViewController:navigationController animated:YES completion:^{}];

UIViewController的进栈和出栈

  • 进栈:
    [self.navigationController pushViewController:VC animated:YES];
    示例代码:

    //我们有一个继承自UIViewController的类SecondPageViewController,创建该类的实例VC
    SecondPageViewController *VC = [[SecondPageViewController alloc] init];    //然后我们使用系统的方法pushViewController:animated:使VC进入navigationController的UIViewController堆栈。
    //此时这个堆栈中的栈顶元素变成了VC,因此navigationController的View部分展示的内容就变成了VC的View,所以画面进行了切换
    [self.navigationController pushViewController:VC animated:YES];
  • 出栈

  1. 使UIViewController中最顶层的元素出栈
    [self.navigationController popViewControllerAnimated:YES];
    执行这句话后,UIViewController中最顶层的元素出栈,所以堆栈中处于栈顶的元素发生了变化,navigationController中间的View也发生了变化,直观感觉就是退回了上一个页面。但是当堆栈中的元素只有一个时该方法无效,因为该堆栈中必须要保证至少要有一个元素。

  2. pop到指定的元素
    假设现在UIViewController堆栈中有四个元素,从栈底到栈顶依次是VC1,VC2,VC3,VC4。我们现在正处在VC4的View中。那么现在我们想直接退到VC2的页面,可以这样做:

[self.navigationController popToViewController:self.navigationController.viewControllers[1] animated:YES];

这个方法实际上是使堆栈中这个指定的viewcontroller上面的元素全部出栈,这样这个指定的viewcontroller就成了栈顶元素,直观感觉是回退到了这个视图控制器的页面。

  1. 直接pop到根视图控制器
    这个其实和上面的道理是一样的,就是使除栈底之外的其它视图控制器全部出栈,这样栈底的根视图控制器也是栈顶元素了。
    [self.navigationController popToRootViewControllerAnimated:YES];

UINavigationBar

  • UINavigationBar是UINavigationController的View的上面的那部分。UINavigationController负责创建UINavigationBar。而UINavigationBar的内容则是由处于UIViewController堆栈顶部的UIViewController的navigationItem这个属性来管理的。

UINavigationBar的外观管理

  • 1.设置style

    //设置bar的style
    self.navigationController.navigationBar.barStyle = UIBarStyleDefault;//这种设置是白底黑字
    self.navigationController.navigationBar.barStyle = UIBarStyleBlack; //这种设置是黑底白字
    1. 设置是否隐藏
      self.navigationController.navigationBar.hidden = YES;

  • 3.设置背景颜色
    self.navigationController.navigationBar.barTintColor = [UIColor redColor];

    1. 设置字体颜色
      self.navigationController.navigationBar.tintColor = [UIColor blackColor];

    1. 设置标题字体属性

self.navigationController.navigationBar.titleTextAttributes = @{NSFontAttributeName: [UIFont systemFontOfSize:30], NSForegroundColorAttributeName: [UIColor whiteColor]};

UINavigationBar的内容设置

  • 前面说过UINavigationBar的内容是由处于UIViewController堆栈栈顶的UIViewController的navigationItem属性来配置的。

  • UINavigationBar和navigationItem有什么联系?

UINavigationBar是UINavigationController的属性,我们在设置了UINavigationBar的外观后,其将作用于全部的UIViewController。navigationItem是UIViewController的属性,它是配置这个UIViewController上面的UINavigationBar的内容的。UINavigationBar中有一个堆栈,这个堆栈是一个UINavigationItem堆栈,当把一个UIViewController push进栈的时候,它的navigationItem也会被push进UINavigationBar的堆栈。所以UINavigationBar的这个堆栈和这个UIViewController堆栈是一一对应的。

UINavigationItem堆栈

我们看到UINavigationBar有一个Items属性,这个items属性就是以堆栈的形式存放每个UIViewController的navigationItem。其中栈顶的navigationItem称为topItem,栈顶下面的item称为backItem。

  • UINavigationBar通过UINavigationItem堆栈按照如下方式来决定展示在UINavigationBar中的内容:
    位于中间的标题会按照下面的顺序展示内容:

如果topitem设置了标题视图(titleview属性),则展示标题视图。
如果topitem设置了标题文字(title属性),则显示标题文字。
如果,什么也没有设置,则显示空白。

位于右边的按钮按照下面的顺序展示内容:

如果topitem设置了右侧按钮(rightBarButtonItem属性),则显示右侧按钮。
如果没有设置右侧按钮,则显示空白。

位于左侧的按钮会按照下列顺序显示内容:

如果topitem设置了左侧按钮(leftBarButtonItem属性),则显示左侧按钮。
如果backitem设置了返回按钮(backButtonItem属性),则显示返回按钮。
如果backitem设置了标题文字(title属性),则显示利用标题文字封装的返回按钮。

如果以上都未设置,则展示利用“Back”封装的返回按钮。

tips

在默认情况下返回按钮和左侧按钮是不同时显示的,默认是不显示左侧按钮,要使两者同时显示,可以设置:
UINavigationBar通过UINavigationItem堆栈按照如下方式来决定展示在UINavigationBar中的内容

tips

修改返回按钮的标题
//在这个页面设置,下个页面生效。
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"go" style:UIBarButtonItemStylePlain target:nil action:nil];

设置返回按钮的图片:

self.navigationController.navigationBar.backIndicatorImage = [UIImage imageNamed:@""];self.navigationController.navigationBar.backIndicatorTransitionMaskImage = [UIImage imageNamed:@""];

这两句话必须同时设置才会生效。

通过手势隐藏UINavigationBar与UIToolbar

获取手势识别器

// 侧滑返回手势识别器@property(nonatomic, readonly) UIGestureRecognizer *interactivePopGestureRecognizer;// 用于轻拍隐藏UINavigationBar与UIToolbar的手势识别器@property(nonatomic, readonly, assign) UITapGestureRecognizer *barHideOnTapGestureRecognizer;// 用于轻扫隐藏UINavigationBar与UIToolbar的手势识别器@property(nonatomic, readonly, strong) UIPanGestureRecognizer *barHideOnSwipeGestureRecognizer;// 示例UIGestureRecognizer *interactivePopGestureRecognizer = navigationController.interactivePopGestureRecognizer;

隐藏UINavigationBar

//这样设置是对堆栈中的所有viewcontroller生效//轻拍隐藏,再次轻拍显示
    self.navigationController.hidesBarsOnTap = YES;//向上轻扫隐藏,向下轻扫显示
    self.navigationController.hidesBarsOnSwipe = YES;//横屏隐藏(此时轻拍显示),竖屏显示.
    self.navigationController.hidesBarsWhenVerticallyCompact = YES;//键盘出现隐藏,键盘消失仍隐藏,但是轻点出现。
    self.navigationController.hidesBarsWhenKeyboardAppears = YES;


作者:雪山飞狐_91ae
链接:https://www.jianshu.com/p/f2598a8a816d