最近在研究ios 随身版monkey,monkey需要有发送back事件的能力。对于android实现比较简单,因为系统本身就支持back,但是ios本身不支持,这时候就需要寻找controller的返回按钮。
1、controller返回按钮的一般实现
要寻找controller的返回按钮,就需要了解controller是如何实现返回的,这里面先定义两个概念,即previousController和currentController,previousController表示前一个Controller,而currentController表示当前界面显示的Controller,关系如下图所示。

1.1 通过currentController的 self.navigationItem.leftBarButtonItems实现
通常使用leftBarButtonItems的方式是为了控制返回按钮的间距,一般常用代码模式如下:
NSMutableArray *barItems = [NSMutableArray array];
//距离左右的间距
UIBarButtonItem *space = xxxx ;
[barItems addObject:spacer];
UIBarButtonItem *barItem;
if(文字按钮){
barItem = [[UIBarButtonItem alloc] initWithTitle:xxx style:UIBarButtonItemStylePlain target:self action:xxxx];
}else if(图片按钮){
barItem = [[UIBarButtonItem alloc] initWithCustomView:xxxx];
}
[barItems addObject:barItem];
self.navigationItem.leftBarButtonItems = barItems
1.2 通过currentController的self.navigationItem.leftBarButtonItem实现
使用 leftBarButtonItem的方式应该是最常用的自定义返回按钮的一种方式,常用代码模式如下:
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:xxx];
self.navigationItem.leftBarButtonItem = item;
或者
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithTitle:xxx style:UIBarButtonItemStylePlain target:self action:xxxx];
self.navigationItem.leftBarButtonItem = item;
1.3 通过previousController的self.navigationItem.backBarButtonItem实现
使用 backBarButtonItem的方式应该是自定义返回按钮的另一种方式,常用代码模式如下:
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:xxx];
self.navigationItem.backBarButtonItem= item;
或者
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithTitle:xxx style:UIBarButtonItemStylePlain target:self action:xxxx];
self.navigationItem.backBarButtonItem= item;
1.4 没有自定义任何返回按钮,使用系统默认按钮
在按钮上显示的文字规则如下:
- 如果previousController有标题(title),则currentController的返回按钮将自动变为该标题
- 如果previousController没有标题(title),在中文环境下,显示“返回”,在英文环境下,显示“Back”
2、UINavigationBar与UINavigationItem的关系
UINavigationController负责创建、配置及管理UINavigationBar, 其通过位于UIViewController堆栈栈顶位置的UIViewController的navigationItem属性来管理UINavigationBar展示的内容, 同时UINavigationController也提供了navigationBar属性, 允许开发者通过该属性设置UINavigationBar的外观。
通俗来讲就是前面通过self.navigationItem进行赋值自定义的返回按钮,其实体现在了 self.navigationController.navigationBar上
self.navigationItem与self.navigationController.navigationBar的对应关系如下图所示:

下面用等号来表示他们之间的对应关系
self.navigationController.navigationBar.topItem.leftBarButtonItems = self.navigationItem.leftBarButtonItems
self.navigationController.navigationBar.topItem.leftBarButtonItem = self.navigationItem.leftBarButtonItem
self.navigationController.navigationBar.backItem.backBarButtonItem = self.navigationItem.backBarButtonItem
self.navigationController.navigationBar.topItem.rightBarButtonItem = self.navigationItem.rightBarButtonItem
3、寻找controller的返回按钮
知道以上原理以后,接下来就是寻找位于左侧返回按钮展示内容的顺序。顺序如下所示:
- 如果topItem设置了左侧按钮组(leftBarButtonItems属性), 则展示左侧按钮组的最后一个UIBarButtonItem
- 如果topItem设置了左侧按钮(leftBarButtonItem属性), 则展示左侧按钮
- 如果backItem设置了返回按钮(backBarButtonItem属性), 则展示返回按钮
- 如果backItem设置了标题文字(title属性), 则展示利用标题文字封装的返回按钮
- 如果以上都未设置, 在中文环境下,显示“返回”,在英文环境下,显示“Back”
4、代码如下
//如果topItem设置了左侧按钮组(leftBarButtonItems属性),则默认使用最后一个item
//如果topItem设置了左侧按钮(leftBarButtonItem属性), 则展示左侧按钮
//如果backItem设置了返回按钮(backBarButtonItem属性), 则展示返回按钮
//如果backItem设置了标题文字(title属性), 则展示利用标题文字封装的返回按钮
//如果当前是中文环境,则展示利用文字”返回”封装的返回按钮
//如果当前是英文环境,则展示利用文字”Back”封装的返回按钮
NSString *back = nil ;
if([FindTopController topController].navigationController.navigationBar.topItem.leftBarButtonItems){
UIBarButtonItem *item = [[FindTopController topController].navigationController.navigationBar.topItem.leftBarButtonItems lastObject] ;
//返回按钮是由UIBarButtonItem的initWithCustomView定义
if(item.customView){
back = item.customView.accessibilityLabel ;
}else{
//如果定义了title
if(item.title){
back = item.title ;
}
}
}else if([FindTopController topController].navigationController.navigationBar.topItem.leftBarButtonItem){
//返回按钮是由UIBarButtonItem的initWithCustomView定义
if([FindTopController topController].navigationController.navigationBar.topItem.leftBarButtonItem.customView){
back = [FindTopController topController].navigationController.navigationBar.topItem.leftBarButtonItem.customView.accessibilityLabel ;
}else{
//如果定义了title
if([FindTopController topController].navigationController.navigationBar.topItem.leftBarButtonItem.title){
back = [FindTopController topController].navigationController.navigationBar.topItem.leftBarButtonItem.title ;
}
}
}else if([FindTopController topController].navigationController.navigationBar.backItem.backBarButtonItem){
//返回按钮是由UIBarButtonItem的initWithCustomView定义
if([FindTopController topController].navigationController.navigationBar.backItem.backBarButtonItem.customView){
back = [FindTopController topController].navigationController.navigationBar.backItem.backBarButtonItem.customView.accessibilityLabel ;
}else{
//如果定义了title
if([FindTopController topController].navigationController.navigationBar.backItem.backBarButtonItem.title){
back = [FindTopController topController].navigationController.navigationBar.backItem.backBarButtonItem.title ;
}
}
}else if([FindTopController topController].navigationController.navigationBar.backItem.title){
back = [FindTopController topController].navigationController.navigationBar.backItem.title ;
}else{
//获取当前语言环境
NSArray *languages = [NSLocale preferredLanguages] ;
NSString* preferredLang = [languages objectAtIndex:0];
//判断当前app是否支持中文环境
NSString *path = [[NSBundle mainBundle] pathForResource:@"zh-Hans" ofType:@"lproj"];
if(path){
back = @"返回" ;
}else{
back = @"Back" ;
}
}
5、另外一种更加优雅的方式返回
if (self.presentingViewController) {
[self dismissViewControllerAnimated:YES completion:nil];
} else {
[self.navigationController popViewControllerAnimated:YES];
}
6、参考文章
1、http://www.liupeng.tech/2017/02/16/UINavigationController%E4%B8%8EUINavigationBar%E8%AF%A6%E8%A7%A3/
2、https://blog.novoda.com/ui-testing-part-2/
3、https://blog.youkuaiyun.com/moon_prince2013/article/details/49079251
4、https://www.jianshu.com/p/32418956c322
本文深入解析iOS中UINavigationController与UINavigationBar的关系,探讨不同场景下返回按钮的实现方式,包括自定义按钮、系统默认按钮及按钮展示顺序。
132

被折叠的 条评论
为什么被折叠?



