iOS-UINavigationController官方文档分析大总结

一、概述

  • 类继承关系如下:UINavigationController
    <- UIViewcontroller <- UIResponder <- NSObject
    .
  • 它是一个容器类视图控制器,以栈的形式管理一组视图控制器,位于栈底的视图是其rootViewController,管理视图控制器个数理论上不受限制(实际受内存限制),push和pop方法来弹入弹出控制器,最多只能显示一个视图控制器,那就是处于栈顶的视图控制器.
  • 如果不给它添加视图控制器也不会报错,界面上也有视图,因为UINavigationController继承自UIViewController,也有自己的view,只不过默认情况下.view.backgroundColor为nil,即透明的。
  • 若不给除根视图控制器之外的其他视图控制器设置返回按钮,UINavigationController会给他们设置返回按钮(<返回).
  • UINavigationController管理的对象有:UINavigationBar,UIToolBar.UIToolBar默认是隐藏的.
  • UINavigationController允许开发者自定义UINavigationBar外观相关的属性,但是其frame bounds alpha不允许直接自定义,除非使用UINavigationBar的子类,
    初始化UINavigationController时,方法为:
    initWithNavigationBarClass:toolbarClass:
  • 自定义UINavigationBar,可使用 UIAppearance,该API是全局修改,常在APPDelegate方法里面使用,比如全局设置标题的字体大小 颜色等.

二、常用函数

初始化函数:

- initWithRootViewController:

- initWithNavigationBarClass:toolbarClass:

跟导航栏相关的函数和属性

使用push方法能将某个控制器压入栈

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;

使用setViewControllers一次压入多个控制器vc1->vc2->vc3,会显示最后的控制器vc3(处于栈顶),代码如下:

UINavigationController *nav = [[UINavigationController alloc] init];
window.rootViewController = nav;// 创建3个测试控制器UIViewController *vc1 = [[UIViewController alloc] init];
vc1.view.backgroundColor = [UIColor blueColor];
UIViewController *vc2 = [[UIViewController alloc] init];
vc2.view.backgroundColor = [UIColor redColor];
UIViewController *vc3 = [[UIViewController alloc] init];
vc3.view.backgroundColor = [UIColor greenColor];// 最终会显示vc3[nav setViewControllers:@[vc1,vc2,vc3] animated:YES];

使用pop方法可以移除栈顶控制器当一个控制器被pop后,控制器内存就被释放了(会调用deinit/dealloc函数):

- (UIViewController *)popViewControllerAnimated:(BOOL)animated;

一层一层的返回不方便,可以直接回到指定的控制器VC_A(处与VC_A与栈顶之间的控制器全被释放),下面代码执行后,VC_A处于栈顶:

- (NSArray *)popToViewController:VC_A animated:(BOOL)animated;

回到根控制器(栈底控制器):

-(NSArray *)popToRootViewControllerAnimated:(BOOL)animated;

获取被管理的控制器

/// 当前管理的所有的控制器
@property(nonatomic,copy) NSArray<__kindof UIViewController *> *viewControllers;/// 栈顶控制器
@property(nullable, nonatomic,readonly,strong) UIViewController *topViewController;
/// 当前可见的VC,可能是topViewController,也可能是当前topViewController present(modal)出来的VC,总而言之就是可见的VC
@property(nullable, nonatomic,readonly,strong) UIViewController *visibleViewController;

注意,topViewController与visibleViewController大部分情况一样,也有可能不同

NavigationBar不常用属性却非常有用的属性

interactivePopGestureRecognizer

关于这个属性的小结:

  • 注意:从iOS7开始,系统为UINavigationController提供了一个interactivePopGestureRecognizer用于右滑返回(pop),但是,如果自定了back button或者隐藏了navigationBar,该手势就失效了。

  • 所以如果若想使用这个功能,则返回按钮最好使用系统的.

若自定义了返回按钮,又想"右滑返回的手势有效"的解决办法:

在UINavigationController基类中添加代码如下:

遵守协议是 <UIGestureRecognizerDelegate>

切记:使用此方法时  self.hidesBarsOnSwipe = YES;不能使用,即默认是关闭的,否则会造成冲突,在右滑返回时 会出现navigationBar不正常显示的问题,如有兴趣可自己尝试一下.
- (void)viewDidLoad {
    [super viewDidLoad];
//    self.hidesBarsOnSwipe = YES;
//    self.toolbarHidden = NO;
    self.hidesBottomBarWhenPushed = YES;
    self.interactivePopGestureRecognizer.delegate =  self;

}
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    if (self.viewControllers.count <= 1 ) {
        return NO;
    }
    
    return YES;
}
  • 关于右滑返回的总结是:若想使用该属性,则最好使用系统返回键.

下面这些属性在某些情况下会使用到

  • 在小屏4s 5s上有些PM可能会要求在浏览内容时隐藏导航栏,这个时候就可使用此属性.

hidesBarsOnTap(点击隐藏导航栏,再点击显现,皆有向上/下过度的过程)
hidesBarsOnSwipe(经试验是向上轻扫隐藏,向下轻扫则显现,皆有向上/下过度的过程)
hidesBarsWhenVerticallyCompact
hidesBarsWhenKeyboardAppears
navigationBarHidden
barHideOnTapGestureRecognizer
barHideOnSwipeGestureRecognizer

ToolBar属性

- setToolbarHidden:animated:
toolbarHidden

三、导航条

UINavigationController是做导航用的,具体的操作大部是由导航条来完成,导航条的使用就显得很重要。导航条的内容由控制器的navigationItem属性决定。
1 navigationItem的属性
一般使用self.navigationItem.对应属性来获取属性,或者设置属性。或者使用self.navigationController获取到navigationController,再通过navigationController获取到想要设置的viewController

中间的标题文字

@property(nullable, nonatomic,copy) NSString *title;

中间标题视图

@property(nullable, nonatomic,strong) UIView *titleView;

项目中的常用方法是:

UIImageView *titleView = [[UIImageView alloc]initWithFrame:CGRectMake(SCREEN_WIDTH/2 - 100, 0, 200, 44)];
titleView.image = 图片.
[self.navigationItem.titleView addSubview:titleView];

导航栏附加解释说明,如果设置了此字段,导航栏会高出30个点显示此字段在title正上方
@property(nullable,nonatomic,copy) NSString *prompt;
prompt显示位置


自定义左上角的返回按钮

/// 直接设置
@property(nullable, nonatomic,strong) UIBarButtonItem *leftBarButtonItem;

大部分情况下,我们需要指定左边返回按钮距离左边框的距离,可以如下设定:

//自己项目中的方法
 UIButton *backBt = [UIButton buttonWithType:UIButtonTypeSystem];
 backBt.frame = CGRectMake(0, 0, LabelWidth_20, LabelWidth_20);
 [backBt setBackgroundImage:[UIImage imageNamed:@"回退"] forState:UIControlStateNormal];
 [backBt addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
 self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithCustomView:backBt];
//系统推荐方法如下
UIBarButtonItem *leftItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"gobackItem.png"] style:UIBarButtonItemStylePlain target:self action:@selector(backViewcontroller)];
UIBarButtonItem *fixedItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
// 设置边框距离,个人习惯设为-16,可以根据需要调节fixedItem.width = -16;
self.navigationItem.leftBarButtonItems = @[fixedItem, leftItem];

下图为设置边框距离前后的差别:

没有设置边框距离


设置边框距离后


忽略点:(关于系统返回按钮)

  • 子导航条后退按钮,假设通过VC1 push VC2,那么如果设置VC1.navigationItem.backBarButtonItem就会显示在VC2的左上角返回按钮;
    如果再设置VC2.navigationItem.leftBarButtonItem则会覆盖VC1的设置;
    如果VC1和VC2都没有设置,则会显示默认的backBarButtonItem。
@property(nullable,nonatomic,strong) UIBarButtonItem *backBarButtonItem;
  • push到下一个页面时,若不自定义返回按钮,则会显示默认的返回按钮 "<返回" 字体颜色为系统字体颜色,即backBarButtonItem,且系统的向左平移pop的功能会自己实现.
  • 若自定义了返回按钮 则系统自带的向左平移pop的功能会失效.
  • title的长度不可过长,否则会造成系统返回按钮的 返回 字体消失,只剩余一个<

自定义右上角的按钮,或多个按钮

@property(nullable, nonatomic,strong) UIBarButtonItem *rightBarButtonItem;/// 一次设置多个按钮
@property(nullable,nonatomic,copy) NSArray<UIBarButtonItem *> *rightBarButtonItems;

2 设置navigationItem的字体格式

// 字体大小19,颜色为白色
[nav.navigationBar setTitleTextAttributes:@{NSFontAttributeName:[UIFont systemFontOfSize:19],NSForegroundColorAttributeName:[UIColor whiteColor]}];

四、UIToolBar
UINavigationController自带了一个工具栏,通过[self.navigationController setToolbarHidden:NO];来显示工具栏,工具栏中的内容可以通过viewController的toolbarItems来设置,显示的顺序和设置的NSArray中存放的顺序一致,每一个UIBarButtonItem对象都可以设定点击事件,可以使用系统提供的很多常用风格的对象,也可以根据需求进行自定义,下面举例使用系统提供的样式。

// 1 显示工具条
[self.navigationController setToolbarHidden:NO];
// 2 创建四个UIBarButtonItem
UIBarButtonItem *itemOne = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:nil action:nil];
UIBarButtonItem *itemTwo = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:nil action:nil];
UIBarButtonItem *itemThree = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:nil action:nil];
UIBarButtonItem *itemFour = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSearch target:nil action:nil];
// 间隙
UIBarButtonItem *flexibleItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
// 3 添加到toolbarItemsvc.
toolbarItems = @[itemOne,flexibleItem,itemTwo,flexibleItem,itemThree,flexibleItem,itemFour];

效果如下:


另外,UIToolBar使用的比较少,大部分情况下而是使用另一个导航控制器UITabBarController

五 UINavigationControllerDelegate

有两个常用的方法

// 一般用于传递参数,或者做一些其它处理
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated;

参考:http://www.cnblogs.com/mddblog/p/4556974.html

六 UINavigationBar、UINavigationItem、UIToolbar与UIBarButtonItem四者关系

补充:

1 三者概述

  • UITabBar 上展示的是: UITabBarItem( 其类继承关系为--> UIBarItem --> NSObject)

  • UIToolBar 上展示的是: UIToolBarItem (其类继承关系为-->UIBarButtonItem --> UIBarItem--> NSObject)

  • UINavigationBar 上展示的是: UINavigationItem(包括:titleView leftBarButtonItem leftBarButtonItems rightBarButtonItem rightBarButtonItems) (其类继承关系为--> UIBarButtonItem --> UIBarItem--> NSObject)

2 三者区别

名称 位置 作用 高度 appearance
UITabBar 任意位置(常见底部) 点击前后item发生变化,管理一组视图 49 全局修改UI
UIToolBar 任意位置(常见底部) 一般用作功能性点击 44 全局修改UI
UINavigationBar 顶部 一般初始化UINavigationController时,自动生成UIUINavigationBar,也可以单独使用 44 全局修改UI

NavigaitonBar
是导航栏,位于屏幕的上方,管理整个NavigationController的navigationItem,它类似navigationcontroller一样提供了一个栈来管理UINavigationItem,在编程时,一般只设置每个控制器的navigationItem属性.一个导航控制器管理多个视图控制器(多个视图控制器共享一个导航控制器),而一个导航控制器只有一个UINavigationBar,被管理的多个视图控制器共享这一个UINavigationBar,只要一个视图控制器改变了UINavigationBar的属性则影响是全局的。每个视图控制器都会有属于自己的UINavigationItem,系统会以懒加载的方式创建一个UINavigationItem显示在UINavigationBar中,改变UINavigationItem
只会在当前控制器起作用,不会影响其它控制器。

Toolbar
显示在屏幕底部,是导航控制器的工具栏,一个导航控制器只有一个,在任何被管理的视图控制器地方改变则会都改变。可以一次性添加多个UIBarButtonItem或按钮(包装成UIBarButtonItem后添加),有一个items数组属性。

UIBarButtonItem
是UINavigationItem或者Toolbar具体的一个按钮。

UITabBar外观相关的属性和方法:

自定义TabBar的方法参考:

barStyle
The tab bar style that specifies its appearance.

translucent
A Boolean value that indicates whether the tab bar is translucent.

barTintColor
The tint color to apply to the tab bar background.

itemPositioning
The positioning scheme for the tab bar items in the tab bar.

itemSpacing
The amount of space (in points) to use between tab bar items.

itemWidth
The width (in points) of tab bar items.

tintColor
The tint color to apply to the tab bar items.

backgroundImage
The custom background image for the tab bar.

shadowImage
The shadow image to use for the tab bar.

selectionIndicatorImage
The image to use for the selection indicator.

UINavigationBar外观相关的属性和方法:
backIndicatorImage
The image shown beside the back button.

backIndicatorTransitionMaskImage
The image used as a mask for content during push and pop transitions.

barStyle
The navigation bar style that specifies its appearance.

barTintColor
The tint color to apply to the navigation bar background.

shadowImage
The shadow image to be used for the navigation bar.

tintColor
The tint color to apply to the navigation items and bar button items.

translucent
A Boolean value indicating whether the navigation bar is translucent (YES
) or not (NO
).

- backgroundImageForBarMetrics:
Returns the background image for given bar metrics.

- setBackgroundImage:forBarMetrics:
Sets the background image for given bar metrics.

- backgroundImageForBarPosition:barMetrics:
Returns the background image to use for a given bar position and set of metrics.

- setBackgroundImage:forBarPosition:barMetrics:
Sets the background image to use for a given bar position and set of metrics.

- titleVerticalPositionAdjustmentForBarMetrics:
Returns the title’s vertical position adjustment for given bar metrics.

- setTitleVerticalPositionAdjustment:forBarMetrics:
Sets the title’s vertical position adjustment for given bar metrics.

titleTextAttributes
Display attributes for the bar’s title text.

UIToolBar外观相关的属性和方法:
barStyle
The toolbar style that specifies its appearance.

barTintColor
The tint color to apply to the toolbar background.

tintColor
The tint color to apply to the bar button items.

translucent
A Boolean value that indicates whether the toolbar is translucent (YES
) or not (NO
).

- backgroundImageForToolbarPosition:barMetrics:

- setBackgroundImage:forToolbarPosition:barMetrics:

- shadowImageForToolbarPosition:

- setShadowImage:forToolbarPosition:

关于详细使用方法可参考:UINavigationBar 使用总结:写的很详细.

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

推荐阅读更多精彩内容