iOS学习—— UINavigationController的返回按钮与侧滑返回手势的研究
侧滑返回手势是从iOS7开始增加的一个返回操作,经历了两年时间估计iPhone用户大部分都已经忽略了屏幕左上角那个碍眼的back按钮了。之前在网上搜过有关侧滑手势的技术博客,发现大多比较散乱,甚至有很多都是简单的粘贴复制,并不全面。侧滑返回的操作效果与左上角的back按钮是一样的,所以一起放在这里进行探讨。
导航栏左上角的back按钮是附着在UINavigationController的UINavigationBar里自带的一个返回按钮,导航栏自带的back按钮的图层结构如下图所示。一个UINavigationController只会有一个UIBackButtonContentView,但是可以有多个leftBarButtonItem、rightBarButtonItem(leftBarButtonItem、rightBarButtonItem就在下图所示的UIButtonBarStackView图层下),其中backButton与leftBarButtonItem之间的关系和区别在后面我们会讲到。

一 侧滑返回
侧滑返回是系统iOS7自带的一种方便用户进行返回操作而推出的一种新功能。在开发过程中,对侧滑返回进行控制非常简单,主要就是启动侧滑手势和禁用侧滑手势。首先,我们来看一下 UINavigationController 的 @property ,可以找到下面这个属性。
@property(nullable, nonatomic, readonly) UIGestureRecognizer *interactivePopGestureRecognizer;
1.1 侧滑开启与关闭
UINavigationController的interactivePopGestureRecognizer这个属性就是我们的侧滑返回手势,如果你的项目中没有需求要自定义返回按钮(虽然我觉得这并不太可能),那么你所需要的操作就非常简单了,不多说直接上代码。
self.navigationController.interactivePopGestureRecognizer.enabled = YES; //启用侧滑手势
self.navigationController.interactivePopGestureRecognizer.enabled = NO; //禁用侧滑手势
1.2 侧滑使用注意
侧滑手势在使用中需要注意的一点就是在项目开发中,我们一般是采用的UITabBar + UINavigationController架构,对于每一个UITabBar的item模块,我们都定义一个UINavigationController对该item模块上的viewController进行控制。而在这个模块上,我们有某个或某些viewController需要禁用侧滑手势(一般需要禁用侧滑手势是因为返回或退出当前viewController时需要double confirm,在一些填表的页面比较常见),而其他的viewController则不需要禁用侧滑手势。这时候我们就需要特别小心,因为 self.navigationController.interactivePopGestureRecognizer.enabled = NO; //禁用侧滑手势 是对当前的UINavigationController有效的,所以一旦你在某个界面禁用了侧滑,那么该UINavigationController控制下的所有viewController都会禁用侧滑,这显然是不合理的。提供一个解决方案就是在进入viewController时 - (void)viewDidAppear:(BOOL)animated; 中禁用侧滑手势,然后在离开viewController时 - (void)viewWillDisappear:(BOOL)animated; 开启策划手势。具体代码如下:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
// 禁用返回手势
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
} - (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// 开启返回手势
if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
}
}
1.3 侧滑手势的获取
如果一个页面上有多个手势,我们要如何去获取策划手势,并对其进行操作呢?其实很简单,侧滑手势是一种UIScreenEdgePanGestureRecognizer,所以我们只需要对当前手势的类别进行判断就可以了。具体代码如下:
//获取侧滑返回手势
- (UIScreenEdgePanGestureRecognizer *)screenEdgePanGestureRecognizer
{
UIScreenEdgePanGestureRecognizer *screenEdgePanGestureRecognizer = nil;
if (self.view.gestureRecognizers.count > )
{
for (UIGestureRecognizer *recognizer in self.view.gestureRecognizers)
{
if ([recognizer isKindOfClass:[UIScreenEdgePanGestureRecognizer class]])
{
screenEdgePanGestureRecognizer = (UIScreenEdgePanGestureRecognizer *)recognizer;
break;
}
}
}
return screenEdgePanGestureRecognizer;
}
1.4 UIScrollView与侧滑手势共存问题
UIScrollView及其子类自带滑动手势,所以如果一个viewController钟有UIScrollView及其子类的view时,侧滑手势影响用户体验效果,此时用户将无法通过侧滑进行返回。因为侧滑返回手势事实上是由存在已久的UIPanGestureRecognizer来识别并响应的,它直接与UINavigationController的view进行绑定,因此在包含UIScrollView的viewController中存在如下关系:
UIPanGestureRecognizer ——bind—— UIScrollView
UIScreenEdgePanGestureRecognizer ——bind—— UINavigationController.view
滑动返回无法触发,说明UIScreenEdgePanGestureRecognizer并没有接收到手势事件,也就是说UIScreenEdgePanGestureRecognizer被UIPanGestureRecognizer屏蔽了。因此,我们为了实现侧滑返回手势,我们需要设置两种手势的共存和先后响应问题,我们可以设置UIScrollView的UIPanGestureRecognizer手势在UIScreenEdgePanGestureRecognizer失效时才识别,具体设置方法如下:
//指定滑动手势在侧滑返回手势失效后响应
[self.tableView.panGestureRecognizer requireGestureRecognizerToFail:[self.navigationController screenEdgePanGestureRecognizer]];
二 导航栏的back按钮
在了解导航栏的返回按钮之前,我们先了解一下导航栏管理导航栏上各类控件的UINavigationBar。首先,我们先来看一看官方文档怎么介绍UINavigationBar,A UINavigationBar object is a bar, typically displayed at the top of the window, containing buttons for navigating within a hierarchy of screens. The primary components are a left (back) button, a center title, and an optional right button. You can use a navigation bar as a standalone object or in conjunction with a navigation controller object.组成如下图左边所示。最重要的一部分我用蓝色加粗标出来了,就是说这个UINavigationBar主要是由左右按钮控件、中间标题控件组成。原生的导航条上的返回(back)按钮,一般是显示一个返回箭头+上一页面的标题(或者是 返回箭头+Back),如下图右边所示。

2.1 导航条上的按钮三兄弟
在前面我们也提到了,在导航栏上有左右按钮和返回按钮,官方称谓是backBarButtonItem、leftBarButtonItem、rightBarButtonItem。他们都属于UINavigationItem的组成部分,都显示在navigationBar上,都属于UIBarButtonItem类,所以我给他们取名为导航条上的按钮三兄弟,哈哈哈。。。
首先,我们来说一下leftBarButtonItem、rightBarButtonItem,这两个是孪生兄弟,唯一的区别就是在导航条上的位置,顾名思义,leftBarButtonItem在导航条左侧,rightBarButtonItem在导航条右侧。此外,还有一点需要我们注意的是navigationBar上的leftBarButtonItem、rightBarButtonItem可以有多个,用法也非常简单,常见用法就是一般在 - (void)viewDidLoad 中添加按钮,然后添加按钮的点击功能即可。
//添加取消btn
UIBarButtonItem *cancelBtn = [[UIBarButtonItem alloc] initWithTitle:@"取消" style:UIBarButtonItemStylePlain target:self action:@selector(navBtnPress:)] ;
cancelBtn.tag = ;
self.navigationItem.leftBarButtonItem = cancelBtn ;
//添加完成btn
UIBarButtonItem *createBtn = [[UIBarButtonItem alloc] initWithTitle:@"完成" style:UIBarButtonItemStylePlain target:self action:@selector(navBtnPress:)] ;
createBtn.enabled = NO ; //刚开始设置为不可选
createBtn.tag = ;
self.navigationItem.rightBarButtonItem = createBtn ;
/**
导航栏 取消 完成 按钮的操作
@param sender <#sender description#>
*/
- (void) navBtnPress:(UIButton *)sender{
if (sender.tag == ) {
//取消
NSLog(@"cancel");
} else {
//完成
NSLog(@"create");
}
}
2.2 导航条上的backBarButtonItem
同样的,我们首先从官方文档了解一下backBarButtonItem的描述:When this navigation item is immediately below the top item in the stack, the navigation controller derives the back button for the navigation bar from this navigation item. When this property is nil, the navigation item uses the value in its title property to create an appropriate back button. If you want to specify a custom image or title for the back button, you can assign a custom bar button item (with your custom title or image) to this property instead. When configuring your bar button item, do not assign a custom view to it; the navigation item ignores custom views in the back bar button anyway.说明了backBarButtonItem只能自定义image和title,不能重写target or action,系统会忽略其他的相关设置项。
Note: If the title of your back button is too long to fit in the available space on the navigation bar, the navigation bar may substitute the string “Back” in place of the button’s original title. The navigation bar does this only if the back button is provided by the previous view controller. If the new top-level view controller has a custom left bar button item—an object in the leftBarButtonItems or leftBarButtonItem property of its navigation item—the navigation bar does not change the button title.这段描述了关于backBarButtonItem的一些特殊点,如果你上一级设置的backBarButtonItem的标题过长(没有设置则默认是上一级标题),那么系统可能会自动用“Back/返回”来代替返回按钮中的标题。此外,如果是自定义的左按钮,则系统不会修改其值。
2.3 backBarButtonItem和leftBarButtonItem的区别
- backBarButtonItem和另外两兄弟是有区别的,比如当前有AController准备push到BController,设置backBarButtonItem的title和image需要在AController内设置,在调用AController Push:B之前进行设置, AController.navigationItem.backBarButtonItem = .... ,其他两兄弟则是在BController的ViewDidload后设置均可。所以,如果我们一定需要重写返回键的action做一些其他的工作,则需要自定义一leftBarButtonItem,因为系统定义leftBarButtonItem的显示优先级比backBarButtonItem优先级高,当存在leftBarButtonItem时,自动忽略backBarButtonItem,达到重写backBarButtonItem的目的。
- backBarButtonItem的自定义不会影响系统的侧滑返回手势,而leftBarButtonItem的自定义则会禁用侧滑返回手势。
UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];
//对按钮的个性化设定
UIBarButtonItem *barItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
self.navigationItem.leftBarButtonItem = barItem; //侧滑手势失效
self.navigationItem.backBarButtonItem = barItem; //不影响侧滑手势 - backBarButtonItem的自定义不能影响返回按钮的标题和图片,不会隐藏最左边的返回箭头backIndicatorImage,而leftBarButtonItem的自定义则会使最左边的返回箭头消失backIndicatorImage。

2.4 各个对象下的backBarButtonItem的区别
这一部分参考自:http://blog.csdn.net/dreamno23/article/details/21085783,还有些没弄明白,后面有时间再理一理这一块。
对于导航栏上的按钮三兄弟,我们在3个类下面都能发现他们,比如当前在一个UIViewController内,输入以下方法都能发现他们。(同leftBarButtonItem | rightBarButtonItem)
self.navigationItem.backBarButtonItem self.navigationController.navigationItem.backBarButtonItem self.navigationController.navigationBar.backItem.backBarButtonItem
比如在AController->BController,在A设置了self.navigationItem.backBarButtonItem,经过试验发现,这个backBarButtonItem为BController的self.navigationController.navigationBar.backItem.backBarButtonItem。
UIViewController的属性navigationItem正是被当前UINavigationBar--[UINavigationBar appearance]管理的属性
//The navigation item used to represent the view controller in a parent’s navigation bar. (read-only)
@property(nonatomic, readonly, retain) UINavigationItem *navigationItem;
self.navigationController.navigationItem.backBarButtonItem则是表示当前navigationController的parent的UINavigationBar,一般情况下没有这样的嵌套。
iOS学习—— UINavigationController的返回按钮与侧滑返回手势的研究的更多相关文章
- iOS如何把导航默认的返回按钮设置成“返回”
版权声明:本CSDN博客所有文章不更新,请关注标哥博客:http://www.henishuo.com/ - (void)addBackItemWithAction:(SEL)action { if ...
- Swift - 修改导航栏“返回”按钮文字和图标 /手势冲突解决/响应范围
iOS11之前 修改导航栏“返回”按钮文字,图标 https://blog.csdn.net/u012701023/article/details/50264265 iOS11 完美解决导航栏按钮偏移 ...
- iOS-自定义NavigationItem返回按钮【pop返回按钮】
在用navigationVC时,返回按钮有时候不想用系统的,这里用继承的方式把按钮替换了,同时也可以实现系统的右滑返回,很简单: 1.创建基类 BasePopViewController 创建一个用于 ...
- 使用HBuilderX打包成app之后点击返回按钮让它返回上一个页面
首先:下载引入mui.min.js文件,MUI框架mui-min.js文件github地址 https://github.com/dcloudio/mui 下载之后并在index.html文件中引入如 ...
- iOS开发之自定义导航栏返回按钮右滑返回手势失效的解决
我相信针对每一个iOS开发者来说~除了根视图控制器外~所有的界面通过导航栏push过去的界面都是可以通过右滑来返回上一个界面~其实~在很多应用和APP中~用户已经习惯了这个功能~然而~作为开发者的我们 ...
- iOS: 学习笔记, 动态添加按钮
1. 新建iOS -> Single View Application. 2. 个性控制器文件YYViewController.m(此处修改为你相应的控制器文件名) // // YYViewCo ...
- 关于iOS自定义返回按钮右滑返回手势失效的解决:
在viewDidLoad方法里面添加下面这一句代码即可 self.navigationController.interactivePopGestureRecognizer.delegate=(id)s ...
- ios 修改导航栏返回按钮的图片
修改导航栏返回按钮的图片 方法1: [UINavigationBar appearance].backIndicatorTransitionMaskImage = [UIImage imageName ...
- IOS让返回按钮显示自定义标题而不是上个ViewController的title
在开发IOS的时候发现当从一个ViewController跳转到另一个ViewController时,被跳转到的那个ViewController的返回按钮总是显示的是上个ViewController的 ...
随机推荐
- Lonlife 1000 - Spoon Devil's 3-D Matrix
1000 - Spoon Devil's 3-D Matrix Time Limit:1s Memory Limit:32MByte Submissions:208Solved:65 DESCRIPT ...
- ViewPager使用记录3——循环展示
ViewPager是v4支持库中的一个控件,相信几乎所有接触Android开发的人都对它不陌生.之所以还要在这里翻旧账,是因为我在最近的项目中有多个需求用到了它,觉得自己对它的认识不够深刻.我计划从最 ...
- 初识java这个小姑娘(一)
忽然想起这样一个场景:那时我还是小学三年级的一个小学生,上课的铃声响起,文艺委员起头,大家开始胡乱的开始唱歌,"让我们荡起双桨,小船儿推开波浪",歌声在一片稚气中慢慢停止.我们的语 ...
- 利用KindEditor实现公司通讯录的维护
引言: 本人所属施工单位,在建项目较多,通讯录是以项目为单位挂接在公司内部网站通讯录板块,以静态页面展示.一直以来都是项目部办公室通过电话.邮件等方式通知总部信息部门变更通讯录,日常维护的工作量较大. ...
- Windows中根据端口定位持有者程序
之前被一个问题所困扰, 电脑过一段时间就无法上网, 查询netstat, 会有大量的端口被占用, 但是看不出来是哪个程序开启的 ( 最终定位到是ADSafe搞得鬼 ) . 后来发现几个命令可以根据端口 ...
- mybatis延迟加载一对多
1.实体类 package cn.bdqn.bean; import java.util.Set; /** *国家的实体类 */ public class Country { private Inte ...
- [亲测]ASP.NET Core 2.0怎么发布/部署到Ubuntu Linux服务器并配置Nginx反向代理实现域名访问
前言 ASP.NET Core 2.0 怎么发布到Ubuntu服务器?又如何在服务器上配置使用ASP.NET Core网站绑定到指定的域名,让外网用户可以访问呢? 步骤 第1步:准备工作 一台Liun ...
- Java开发小技巧(一)
前言 相信许多程序员在看别人写的代码的时候,会有怀疑人生的感想,面对一堆天书一样的代码,很难摸清作者的思路,最后选择了重构,如果你认同上面这个作法,说明了两个问题:要么原来的开发者技术菜.要么你技术菜 ...
- CSS中line-height与vertical-align
参考文章: 深入了解CSS的line-height属性 Vertical-Align: 你需要知道的所有事[译] Vertical-Align: All You Need To Know 1.什么是行 ...
- Navicat for Mysql 暴力破解教程
关于破解Navicat for MySQL的教程有很多 ,但是比较繁琐, 这里推荐一种比较简单的办法~ 网盘地址:链接: https://pan.baidu.com/s/1kVHyShL 密码: ws ...