UINavigationController

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;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,527评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,314评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,535评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,006评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,961评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,220评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,664评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,351评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,481评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,397评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,443评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,123评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,713评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,801评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,010评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,494评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,075评论 2 341