2018-07-11 UINavigationController和UINavigationBar

在做View Controller的生命周期的时候,由于要用到UINavigationController,就干脆继续学习了一波这个知识点,参考了这篇文章

一.定义

UINavigationController(导航控制器)是一个容器控制器,其内部有多个UIViewController(视图控制器)的内容,我们可以通过UINavigationControllerview属性获取到其自身的视图,在该视图上面有一个位于界面顶部的UINavigationBar(导航栏)和位于界面底部的默认隐藏的UIToolbar(工具栏),以及一个位于界面中间部分的UIViewControllerview

UINavigationController层级结构

当用户在UINavigationController的层级结构中来回切换的时候,UINavigationBarUIToolbar的内容会随之发生变化,但是其本身并不会发生变化,唯一发生变化的就是位于界面中间部分的UIViewControllerview

二.UIViewController堆栈的管理

UINavigationController通过其管理的UIViewController堆栈来决定展示在UINavigationController中间部位的内容,该内容由位于UIViewController堆栈的栈顶位置的UIViewController决定。

下图的View ControllersUIViewController堆栈navigationBar是位于顶部的UINavigationBartoolBar是位于底部的UIToolbar

UIViewController堆栈

根据栈的定义,如果我们要实现这个栈的内容,既可以用push和pop对UIViewController进行操作,也可以直接设置UIViewController堆栈的内容。

1.push

//push
//方法一
/*
 * 参数一: UIViewController, 该参数不可以使用UITabBarController的实例
 * 参数二: 是否执行动画
 */
[navigationController pushViewController:[[UIViewController alloc] init] animated:YES];

//方法二
/*
 * 参数一: UIViewController, 该参数不可以使用UITabBarController的实例
 * 参数二: 要求展示UIViewController的对象
 */
[navigationController showViewController:[[UIViewController alloc] init] sender:nil];

2.pop

//pop一个UIViewController
/*
 * 参数一: 是否执行动画
 * 返回值: 从UIViewController堆栈中Pop出来的UIViewController
 */
UIViewController *viewController = [navigationController popViewControllerAnimated:YES];

//一直pop到根视图控制器
/*
 * 参数一: 是否执行动画
 * 返回值: 从UIViewController堆栈中Pop出来的UIViewController数组
 */
NSArray *viewControllers = [navigationController popToRootViewControllerAnimated:YES];

//一直pop到指定的UIViewController
/*
 * 参数一: 指定UIViewController, 该UIViewController必须位于当前UIViewController堆栈中
 * 参数二: 是否执行动画
 * 返回值: 从UIViewController堆栈中Pop出来的UIViewController数组
 */
NSArray *viewControllers = [navigationController popToViewController:navigationController.viewControllers[0] animated:YES];

3.获取

// 获取位于UIViewController堆栈栈顶位置的UIViewController
UIViewController *viewController = navigationController.topViewController;

三.UINavigationBar的管理

UINavigationController通过位于UIViewController堆栈栈顶位置的UIViewControllernavigationItem属性(该属性位于UIViewControllerUINavigationControllerItem类目中)来管理UINavigationBar展示的内容,同时UINavigationController也提供了navigationBar属性, 允许开发者通过该属性设置UINavigationBar的外观。

值得注意的是,UINavigationControllerUINavigationBardelegate, 其负责响应该UINavigationBarDelegate的代理方法, 并据此更新位于界面中间部分的UIViewController的视图。

1.设置UINavigationBar的外观

我们可以通过该属性设置UINavigationBar的外观, 但是不要通过该属性设置其frame, bounds, alpha等属性, 更不要修改其层级结构。

// 属性
@property(nonatomic, readonly) UINavigationBar *navigationBar;
// 示例
navigationController.navigationBar.barStyle = UIBarStyleDefault;

2.设置UINavigationBar的隐藏状态

// 属性
@property(nonatomic, getter=isNavigationBarHidden) BOOL navigationBarHidden;
// 示例
navigationController.navigationBarHidden = YES;

3.设置UINavigationBar的隐藏状态(可选动画)

// 方法
/*
 * 参数一: 隐藏状态
 * 参数二: 是否执行动画
 */
- (void)setNavigationBarHidden:(BOOL)hidden animated:(BOOL)animated;
// 示例
[navigationController setNavigationBarHidden:YES animated:YES];

四.UIToolbar的管理

UINavigationController通过位于UIViewController堆栈栈顶位置的UIViewControllertoolbarItems属性(该属性位于UIViewControllerUINavigationControllerContextualToolbarItems类目中)来管理UIToolbar展示的内容,同时UINavigationController也提供了toolbar属性, 允许开发者通过该属性设置UIToolbar的外观。

1.设置UIToolbar的外观

// 属性
@property(nonatomic, readonly) UIToolbar *toolbar;
// 示例
navigationController.toolbar.barStyle = UIBarStyleDefault;

2.设置UIToolbar的隐藏状态

// 属性
@property(nonatomic, getter=isToolbarHidden) BOOL toolbarHidden;
// 示例
navigationController.toolbarHidden = NO;

3.设置UIToolbar的隐藏状态(可选动画)

// 方法
/*
 * 参数一: 隐藏状态
 * 参数二: 是否执行动画
 */
- (void)setToolbarHidden:(BOOL)hidden animated:(BOOL)animated;
// 示例
[navigationController setToolbarHidden:NO animated:YES];

五.手势识别器的管理

1.获取手势识别器

// 侧滑返回手势识别器
@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;

2.通过手势隐藏UINavigationBar与UIToolbar

// 轻拍隐藏、再次轻拍显示
@property(nonatomic, readwrite, assign) BOOL hidesBarsOnTap;
// 向上轻扫隐藏、向下轻扫显示
@property(nonatomic, readwrite, assign) BOOL hidesBarsOnSwipe;
// 横屏隐藏(此时轻拍显示)、竖屏显示
@property(nonatomic, readwrite, assign) BOOL hidesBarsWhenVerticallyCompact;
// 键盘出现隐藏、键盘消失保持隐藏(此时轻拍显示)
@property(nonatomic, readwrite, assign) BOOL hidesBarsWhenKeyboardAppears;
// 示例
navigationController.hidesBarsOnTap = YES;

六.UINavigationController对象的初始化

//通过UIViewController初始化
/*
 * 参数一: UIViewController, 该参数不可以使用UITabBarController的实例
 */
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:[[UIViewController alloc] init]];

//通过UINavigationBar、UIToolbar初始化
/*
 * 参数一: 自定义UINavigationBar的子类, 如果是nil则为UINavigationBar类
 * 参数二: 自定义UIToolbar的子类, 如果是nil则为UIToolbar类
 */
UINavigationController *navigationController = [[UINavigationController alloc] initWithNavigationBarClass:[UINavigationBar class] toolbarClass:[UIToolbar class]];

七. UINavigationBar

1.概述

UINavigationBar是一个在层级结构中起导航作用的视觉控件, 其一般展示形式如下图所示

2.UINavigationItem堆栈的管理

UINavigationBar虽然继承自UIView, 但是其并非通过addSubview:方法来添加子视图, 而是通过其管理的UINavigationItem堆栈来决定展示在UINavigationBar中的内容。

如下图所示,其中:
itemsUINavigationItem堆栈;
topItem是位于UINavigationItem堆栈栈顶位置的UINavigationItem;
backItem是位于UINavigationItem堆栈栈顶下方位置的UINavigationItem

我们可以利用系统提供的方法向UINavigationItem堆栈中Push一个UINavigationItem, 从UINavigationItem堆栈中Pop一个UINavigationItem, 也可以直接设置UINavigationItem堆栈中的全部UINavigationItem

3. UINavigationBar的内容

UINavigationBar通过UINavigationItem堆栈按照如下方式来决定展示在UINavigationBar中的内容

位于中间的标题会根据下方顺序选择展示的内容:

  • 如果topItem设置了标题视图(titleView属性), 则展示标题视图

  • 如果topItem设置了标题文字(title属性), 则展示标题文字

  • 如果以上都未设置, 则展示空白

位于右侧的按钮会根据下方顺序选择展示的内容:

  • 如果topItem设置了右侧按钮(rightBarButtonItem属性), 则展示右侧按钮

  • 如果以上都未设置, 则展示空白

位于左侧的按钮会根据下方顺序选择展示的内容:

  • 如果topItem设置了左侧按钮(leftBarButtonItem属性), 则展示左侧按钮

  • 如果backItem设置了返回按钮(backBarButtonItem属性), 则展示返回按钮

  • 如果backItem设置了标题文字(title属性), 则展示利用标题文字封装的返回按钮

  • 如果以上都未设置, 则展示利用文字"Back"封装的返回按钮(前提是UINavigationItem堆栈中有超过一个的UINavigationItem

// 初始化UINavigationItem对象
/*
 * 参数一: 标题文字
 */
- (instancetype)initWithTitle:(NSString *)title;
// 示例
UINavigationItem *navigationItem = [[UINavigationItem alloc] initWithTitle:@"Owen"];

//设置标题文字
// 属性
@property(nonatomic, copy) NSString *title;
// 示例
navigationItem.title = @"Title";

//设置标题视图
// 属性
@property(nonatomic, strong) UIView *titleView;
// 示例
navigationItem.titleView = [UIButton buttonWithType:UIButtonTypeInfoLight];

//设置提示文字
// 属性
@property(nonatomic, copy) NSString *prompt;
// 示例
navigationItem.title = @"Prompt";

//设置返回按钮
// 属性
@property(nonatomic, strong) UIBarButtonItem *backBarButtonItem;
// 示例
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Owen" style:UIBarButtonItemStylePlain target:nil action:nil];
navigationItem.backBarButtonItem = barButtonItem;

4.UINavigationBar的外观

UINavigationBar类中提供了大量属性/方法用于设置其外观, 我们可以设置其样式、背景颜色、色彩颜色、文字属性等

同样, 我们也可以设置其背景图片、阴影图片等

//设置样式
//该属性默认为UIBarStyleDefault(白底黑字), 可选项为UIBarStyleBlack(黑底白字)
navigationBar.barStyle = UIBarStyleDefault;

//设置透明性
navigationBar.translucent = YES;

//设置背景颜色
navigationBar.barTintColor = [UIColor orangeColor];

//设置色彩颜色
navigationBar.tintColor = [UIColor greenColor];

//设置标题文字属性
navigationBar.titleTextAttributes = @{NSFontAttributeName: [UIFont systemFontOfSize:30], NSForegroundColorAttributeName: [UIColor whiteColor]};

//设置/获取背景图片
/*
 * 参数一: 背景图片
 * 参数二: 默认为UIBarPositionAny(不指定), 可选项为UIBarPositionBottom(在容器下方), UIBarPositionTop(在容器上方), UIBarPositionTopAttached(在屏幕上方, 与容器平级)
 * 参数三: 可选项为UIBarMetricsDefault(竖屏, 横屏未设置也使用该效果), UIBarMetricsCompact(横屏), UIBarMetricsDefaultPrompt(拥有提示文字的竖屏, 横屏未设置也使用该效果), UIBarMetricsCompactPrompt(拥有提示文字的横屏)
 */
[navigationBar setBackgroundImage:[UIImage imageNamed:@""] forBarPosition:UIBarPositionTop barMetrics:UIBarMetricsDefault];

//设置阴影图片
navigationBar.shadowImage = [UIImage imageNamed:@""];

//设置返回按钮图片(需要同时设置)
navigationBar.backIndicatorImage = [UIImage imageNamed:@""];
navigationBar.backIndicatorTransitionMaskImage = [UIImage imageNamed:@""];
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容