原文地址:http://weizhe.me/ios-7-back-gesture-sample/
在智能机越来越普及,屏幕越做越大的当下,滑动返回手势已经成为了一个应用的标配功能,甚至可以说,不能滑动返回是一种反人类的交互体验。
滑动返回现在大致有以下3种类型:
- 使用
UISwipeGestureRecognizer
实现,效果为用户在屏幕中向右轻扫手指,页面返回。 - 使用
UIPanGestureRecognizer
实现,效果为用户在屏幕中向右滑动手指,松开后页面返回。 - 使用
iOS 7
提供的滑动返回实现,效果为用户手指从屏幕外由左向右进入屏幕,松开后页面返回。
前两种实现方式是 iOS 7
推出之前的普遍做法,现在来看,已经过时且体验不佳,个人推荐使用第三种,优点如下:
- 良好的交互与动画效果
- 系统级的支持,实现简单,代码清晰
- 不会与一些屏幕内的手势产生冲突
虽然优点很明显,但是在使用过程中,还是会有一些值得我们注意的问题,接下来我们就一一解决它们。
1. 如何设置自定义的返回按钮图片?
如果我们的返回按钮不需要显示文字,或者显示的文字是固定的,可以做到图片中去,那么我推荐通过设置 iOS 7
新引入的 backIndicatorImage
来自定义返回按钮。代码如下:
这样设置后会发现图片被渲染成 navigationBar
的 tintColor
的颜色了,要怎样才能显示出原始的图片颜色呢?还需要用到 iOS 7
中 UIImage
的一个新属性 renderingMode
。 我们需要生成一张 renderingMode
为 UIImageRenderingModeAlwaysOriginal
的图片,让我们加上这行代码:
这样我们的图片就能显示出原始的颜色了。
2. 使用 UIButton 自定义返回按钮后,如何使用系统的滑动返回?
当我们的返回按钮上需要显示不同的文字时,就不能使用 backIndicatorImage
了,我们要自定义一个 UIButton
来生成 UIBarButtonItem
,再设置 navigationBar
的 leftBarButtonItem
。而如果设置了 leftBarButtonItem
的话,会使系统的滑动返回失效。我们需要在 UIViewController
中加入这行代码
运行起来一看,恩…可以滑动返回了。
3. 怎样让滑动返回像默认的效果一样容易触发?
玩了一会儿你发现,好像哪里不对劲,怎么不如之前容易触发了?
没错,当设置了 navigationController.interactivePopGestureRecognizer.delegate
后,虽然滑动返回恢复了,但是它却有点“残疾”,具体表现为两点:
- 手指滑动的角度必须要几乎水平,而正常的效果可以接受差不多30度的偏差,这在实际使用过程中的体验差别是非常巨大的。
- 如果
UIViewController
中是一个UITableView
或者其他可滚动的UIScrollView
,那么在UIScrollView
滚动的时候,是不能触发滑动返回的,而正常的效果是可以触发的。
那么,我们该怎样解决这两个问题呢?
我们差不多能猜到是因为手势冲突导致的,那我们就先让 ViewController
同时接受多个手势吧。加上代码:
运行试一试,两个问题同时解决,不过又发现了新问题,手指在滑动的时候,被 pop
的 ViewController
中的 UIScrollView
会跟着一起滚动,这个效果看起来就很怪(知乎日报现在就是这样的效果),而且也不是原始的滑动返回应有的效果,那么就让我们继续用代码来解决吧。
加上这段代码后,系统的 UIScreenEdgePanGestureRecognizer
就不会与其他的手势同时触发,从而解决了这个看起来有点奇怪的效果。
4. 其他若干小问题
让我们继续玩儿啊玩儿,还会遇到哪些问题呢?
- 当在
UINavigationController
的rootViewController
中做一个会触发滑动返回的操作后,再点击某个会pushViewController
的按钮时,UINavigationController
没有任何反应,而如果使用home键
返回主屏,再进入应用的话,会发现已经push
进刚才应该进入的ViewController
了,这是因为在UINavigationController
的rootViewController
中触发了滑动返回导致的,我们只要判断一下当前ViewController
是否是rootViewController
,然后在- gestureRecognizerShouldBegin:
中返回就可以了。 - 如果我们在
pushViewController
的动画过程中触发滑动返回,会导致闪退,处理方式也很简单,在push
之后禁用interactivePopGestureRecognizer
, 在ViewController
显示之后恢复interactivePopGestureRecognizer
就可以了。我使用了swizzling
方式在Category
中统一处理。
`
我将一份 Demo 放到了 Github 上,欢迎大家下载。
iOS7-NavigationController-Sample