iOS:导航控制器侧滑出栈实现
介绍:在iOS中,导航控制器UINavigationController是默认实现左侧边缘侧滑手势出栈的,但是如果当开发者对导航控制器子控制实现自定义leftBaButtonItem时,这个侧滑功能就会失去效果,此时就需要我们在自定义的NavigationController中手动代码去实现了。有的时候为了提高用户体验,会试着进行全屏的侧滑返回,现在这个技术已经普遍应用到app中。下面就来介绍边缘侧滑和全屏侧滑返回。。。。。
第一种方式:实现左侧边缘侧滑返回(系统自带的边缘侧滑,安全可靠)
// // KJNavgationController.m // // Created by mac on 16/2/22. // Copyright © 2016年 mac. All rights reserved. // #import "KJNavgationController.h" @interface KJNavgationController ()<UIGestureRecognizerDelegate,UINavigationControllerDelegate> @end @implementation KJNavgationController
-(void)viewDidLoad{ [super viewDidLoad]; __weak KJNavgationController *weakSelf = self; if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.interactivePopGestureRecognizer.delegate = weakSelf; self.delegate = weakSelf; } } - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { //控制器入栈过程中禁用手势识别 if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) self.interactivePopGestureRecognizer.enabled = NO; [super pushViewController:viewController animated:animated]; } #pragma mark UINavigationControllerDelegate - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animate { //控制器入栈之后,启用手势识别 if ([self respondsToSelector:@selector(interactivePopGestureRecognizer)]) self.interactivePopGestureRecognizer.enabled = YES; } - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { if ([self.childViewControllers count] == 1) { return NO; } return YES; } - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; } //运行试一试,发现了新问题,手指在滑动的时候,被 pop 的 ViewController 中的 UIScrollView 会跟着一起滚动,这个效果看起来就很怪(知乎日报现在就是这样的效果),而且也不是原始的滑动返回应有的效果,那么就让我们继续用代码来解决吧 - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return [gestureRecognizer isKindOfClass:UIScreenEdgePanGestureRecognizer.class]; } @end
优点:实现简单,导航控制器中对全体viewController的侧滑功能可控,系统API绝对安全可靠,无手势冲突
缺点:侧滑范围局限于左侧
适用需求:只需左侧小范围触发侧滑时的首选实现方案。
第二种方式:实现全屏侧滑返回(并不完善的全屏侧滑)
// // KJNavgationController.m // // Created by mac on 16/2/22. // Copyright © 2016年 mac. All rights reserved. // #import "KJNavgationController.h" @interface KJNavgationController ()<UIGestureRecognizerDelegate> @end @implementation KJNavgationController -(void)viewDidLoad{ [super viewDidLoad]; // 获取系统自带滑动手势的target对象 id target = self.interactivePopGestureRecognizer.delegate; // 创建全屏滑动手势,调用系统自带滑动手势的target的action方法 UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:@selector(handleNavigationTransition:)]; // 设置手势代理,拦截手势触发 pan.delegate = self; // 给导航控制器的view添加全屏滑动手势 [self.view addGestureRecognizer:pan]; // 禁止使用系统自带的滑动手势 self.interactivePopGestureRecognizer.enabled = NO; }
// 什么时候调用:每次触发手势之前都会询问下代理,是否触发。 // 作用:拦截手势触发 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { // 注意:只有非根控制器才有滑动返回功能,根控制器没有。 // 判断导航控制器是否只有一个子控制器,如果只有一个子控制器,肯定是根控制器 if (self.childViewControllers.count == 1) { // 表示用户在根控制器界面,就不需要触发滑动手势, return NO; } return YES; } @end
优点:最简洁的全屏侧滑实现,导航控制器中对全体viewController的侧滑功能可控
缺点:从右边往左边划动也能触发侧滑操作,有手势冲突,并不完美。且调用官方私有API
另外:正是缺点的所在,和Cell的侧滑删除手势也是有冲突的,也就是说,免不了需要解决手势的冲突。
适用需求:最好不用,毕竟缺点明显。(不过这个实现思路,确实值得称赞!)
第三种方式:(集成最简单、功能最全面):
链接地址下载DEMO,具体详情见github:https://github.com/forkingdog/FDFullscreenPopGesture
![](http://upload-images.jianshu.io/upload_images/1214009-c386ac12894b7991.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![](https://images2015.cnblogs.com/blog/791499/201604/791499-20160425233923361-2081530512.gif)
![](https://images2015.cnblogs.com/blog/791499/201604/791499-20160425233928548-1522733147.gif)
优点:最全面的全屏侧滑实现,集成超简单,全体viewController的侧滑功能可控,不过得在ViewController内部去控制,稍微麻烦一点;另外,百度知道团队在维护该DEMO,功能会越来越完善,花样更多。
缺点:调用官方私有API(不过已有上线作品,不影响上线,缺点可以忽略!)
适用需求:目前最好的全屏侧滑实现方案。
第四种方式:创建swipe扫动手势,实现全屏侧滑返回
- (void)viewDidLoad { [super viewDidLoad]; // 添加右滑手势 [self addSwipeRecognizer]; } #pragma mark 添加右滑手势 - (void)addSwipeRecognizer { // 初始化手势并添加执行方法 UISwipeGestureRecognizer *swipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(return)]; // 手势方向 swipeRecognizer.direction = UISwipeGestureRecognizerDirectionRight; // 响应的手指数 swipeRecognizer.numberOfTouchesRequired = 1; // 添加手势 [[self view] addGestureRecognizer:swipeRecognizer]; } #pragma mark 返回上一级 - (void)return { // 最低控制器无需返回 if (self.viewControllers.count <= 1) return; // pop返回上一级 [self popToRootViewControllerAnimated:YES]; } //若在控制器之间跳转时需要做一些事情,可在自定义的控制器里添加下面两个方法 #pragma mark push方法 - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated { // do something you want ... [super pushViewController:viewController animated:animated]; } #pragma mark pop方法 - (UIViewController *)popViewControllerAnimated:(BOOL)animated { // 比如停止网络请求 ... return [super popViewControllerAnimated:animated]; }
优点:用户可以自定义扫动侧滑,没有手势冲突,虽使用官方私有API,但是安全。
缺点:侧滑速度太快,不好控制器,不能中途停止侧滑。
适用需求:根据个人需要决定。
参看链接:
http://www.cocoachina.com/ios/20150811/12897.html
http://www.jianshu.com/p/349636eb3fca