背景介绍 : 在开发过程中,系统自带的某些功能,可能不满足我们的开发需求,所以常常需要我们自定义.当我们自定义导航条上的返回按钮之后,会发现系统自带的滑动返回手势处于失效状态,这是本章主要想解决的问题.
思路 : 既然自定义了导航条上的返回按钮,手势失效,说明系统内部是遵守了手势代理的,我们只需要打印出系统自带的手势就可以设置了.
// 打印系统自带的手势
NSLog(@"%@",self.interactivePopGestureRecognizer);
// 打印结果
<UIScreenEdgePanGestureRecognizer: 0x7fb18a627ce0;
state = Possible; delaysTouchesBegan = YES;
view = <UILayoutContainerView 0x7fb18a626210>;
target= <(action=handleNavigationTransition:,
target=<_UINavigationInteractiveTransition 0x7fb18a627a00>)>
- 注意 : 在打印结果中,系统自带的手势只支持边缘滑动手势,它用的是 UIScreenEdgePanGestureRecognizer手势,只能在控制器的边缘才能出发手势的方法,这样,我们改一下,改成全屏都能出发滑动返回功能.
- 我们来解读一下这个打印结果 :
- 只要触发了UIScreenEdgePanGestureRecognizer这个手势,就会调用_UINavigationInteractiveTransition代理的
只要触发UIScreenEdgePanGestureRecognizer,就会调用_UINavigationInteractiveTransition代理的
handleNavigationTransition这个方法.
说明 : _UINavigationInteractiveTransition代理的这个
handleNavigationTransition方法有滑动返回的功能,只要我们创建新的手势设置这个代理,实现这个方法就可以实现滑动返回的功能了, - 下面我们照葫芦画瓢,实现全屏滑动返回.
- 全屏滑动返回手势: UIPanGestureRecognizer
- 代理: _UINavigationInteractiveTransition
- 代理方法:handleNavigationTransition: (注意代理方法有参数,记得不要遗漏了冒号)
- (void)viewDidLoad {
[super viewDidLoad];
// 设置代理
id target = self.interactivePopGestureRecognizer.delegate;
// 创建手势
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:@selector(handleNavigationTransition:)];
// 设置pan手势的代理
pan.delegate = self;
// 添加手势
[self.view addGestureRecognizer:pan];
// 将系统自带的手势覆盖掉
self.interactivePopGestureRecognizer.enabled = NO;
}
注意了 : 这里一定要设置pan.delegate = self, 不然程序会有假死的状况.(本章重点)
做到这里,可以运行模拟器试一下, 会惊奇的发现,能全屏滑动返回了,但是,回到根控制器后,还是能继续滑动,这不是我们的想要的效果.所以还需要调用手势代理中的一个方法:即是否允许接收触摸事件.
// 表示的意思是:当挡墙控制器是根控制器了,那么就不接收触摸事件,只有当不是根控制器时才需要接收事件.
#pragma mark - UIGestureRecognizerDelegate
// 是否触发手势
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
return self.childViewControllers.count > 1;
}
- 总结: 手势代理中还有很多好用的方法,比如: 是否允许同时接收多个手势事件等方法,都是开发中常用的,可以自己去手势代理的头文件中自学.