侧滑返回的效果
从iOS7开始,系统为
UINavigationController
添加
interactivePopGestureRecognizer
属性,这个属性就是系统提供的右滑返回动画,我们可以通过滑动左边边缘实现
pop
效果。我们可以通过
,如上图所示。 self.navigationController.interactivePopGestureRecognizer.enabled = NO
关闭系统默认的边缘返回动画。
缺点:
- 只能实现边缘拖动,如果从视图除左边边缘以外的部分没有效果。
- 如果
push
到其他界面,如果重写的leftBarButtonItem
就失效了。
如果解决上面两个问题,我们需要重新实现动画效果。系统只提供了边缘手势,而没有提供在任何地方都可以右滑返回的动画,所以这个需要我们自己创建一个UIPanGestureRecognizer
手势。文章后面会具体讲解如何实现。
那么,还有一个问题,也就是如果重写的leftBarButtonItem
系统的边缘手势就失效了,这个该如何解决呢?其实也非常简单,我们只需要在重写leftBarButtonItem
的界面加上下面的代码即可:
self.navigationController.interactivePopGestureRecognizer.delegate = self;
#pragma mark - UIGestureRecognizerDelegate
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
//导航的rootViewController关闭右滑返回功能
if (self.navigationController.viewControllers.count <= 1)
{
return NO;
}
return YES;
}
上面代码可以看出:重新设置了interactivePopGestureRecognizer
对象的代理,interactivePopGestureRecognizer
其实也是UIGestureRecognizer
的一个子类,然后重写gestureRecognizerShouldBegin:
方法,判断导航的根控制器不需要侧滑返回的功能。github下载地址。
提示:
self.navigationItem.leftBarButtonItem = customLeftBarButtonItem; //右滑返回失效
self.navigationItem.backBarButtonItem = customLeftBarButtonItem; //不影响右滑返回
那么,如果实现一个自定义右滑返回呢?代码很简单。
1.自定义一个所有控制器的父类,比如DLBaseViewController
,
然后在DLBaseViewController
的viewDidLoad
方法添加下面代码:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
//1.获取系统interactivePopGestureRecognizer对象的target对象
id target = self.navigationController.interactivePopGestureRecognizer.delegate;
//2.创建滑动手势,taregt设置interactivePopGestureRecognizer的target,所以当界面滑动的时候就会自动调用target的action方法。
//handleNavigationTransition是私有类_UINavigationInteractiveTransition的方法,系统主要在这个方法里面实现动画的。
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] init];
[pan addTarget:target action:NSSelectorFromString(@"handleNavigationTransition:")];
//3.设置代理
pan.delegate = self;
//4.添加到导航控制器的视图上
[self.navigationController.view addGestureRecognizer:pan];
//5.禁用系统的滑动手势
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
#pragma mark - 滑动开始会触发
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
//只有导航的根控制器不需要右滑的返回的功能。
if (self.navigationController.viewControllers.count <= 1)
{
return NO;
}
return YES;
}
下面我们的所有的类都继承DLBaseViewController
即可。滑动界面的任何地方都可以右滑返回。运行效果图如下。Demo下载地址
2.如果有TabbarController,上面的方法还可以用吗?我们创建一个TabbarController的工程,然后测试结果如下:
注意: 上面进入第2页隐藏tabbar,是在storyboard选中TwoViewController
,勾上Hide Bottom Bar on Push
如下图所示:
3.一行代码搞定右滑返回功能。
上面我们把功能代码写到了父类里面,这样的坏处就是必须每个控制器都要继承同一个父类,所以比较麻烦。而且上面的代码每个控制器都需要执行一次,所以效率比较低。基于上面的缺点,然后用runtime
的method swizzling
强大技术封装了一个更简单的方法,一行代码就搞定了。详解demo
/*
开启右滑返回手势
注意:
1.一定要在appDelegate里面开启,并且在UINavigationController初始化之前,否则没有效果。
2.如果用的storyboard,直接在appDelegate类didFinishLaunchingWithOptions开启即可
*/
[DLNavigationTransition enableNavigationTransitionWithPanGestureBack];
注意:由于通过runtime
在UINavigationController
的viewDidLoad
里面添加了手势代码,所以一定要在appDelegate
里面开启,并且在UINavigationController
初始化之前,否则没有效果。如果项目用的是storyboard
,直接在appDelegate
类的didFinishLaunchingWithOptions
开启即可。