全屏滑动返回功能的实现
- 思考为什么系统手势不能全屏滑动?
- 上一节已经分析了滑动返回功能是由interactivePopGestureRecognizer提供的,既然这是一个手势,那么苹果肯定是用这个手势添加到某个View上的屏幕左边边缘附近范围为有效作用区, 并且为这个手续绑定方法用于触发事件的调用, 那么可以
NSLog(@"%@",self.interactivePopGestureRecognizer);
//把这个手势打印出来.输出如下:
<UIScreenEdgePanGestureRecognizer: 0x7fddb1c87140; state = Possible; enabled = NO; delaysTouchesBegan = YES; view = <UILayoutContainerView 0x7fddb1dec1c0>; target= <(action=handleNavigationTransition:, target=<_UINavigationInteractiveTransition 0x7fddb1c86b70>)>>interactivePopGestureRecognizer是由UIScreenEdgePanGestureRecognizer这个类创建的对象,从命名可以得知这个这个类创建的手势只对屏幕边缘有效.target=<_UINavigationInteractiveTransition 0x7fddb1c86b70>)>>从target的类名可以知道 ,这个target不是interactivePopGestureRecognizer(两者的类不一样),那么只可能是interactivePopGestureRecognizer.delegate手势的代理. 可以打印一下出来验证:
NSLog(@"%@",self.interactivePopGestureRecognizer.delegate);
//输出如下:
<_UINavigationInteractiveTransition: 0x7faa49cb8560> action=handleNavigationTransition:这个就是手势触发事件所调用的方法, 从命名可以推测这个方法就是实现滑动返回功能.
- 目标是实现全屏滑动返回, 那么可以自己创建一个新的手势, 添加到NavigationController的view上, 然后学系统的方法一样, 为这个手势绑定事件方法:
id interactivePopGestureRecognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:<_UINavigationInteractiveTransition 0x7f90714a2da0>) action:handleNavigationTransition:]
// 只要能拿到interactivePopGestureRecognizer的target的action就有滑动返回功能
// 实现全屏滑动: 滑动返回功能 => 苹果已经帮我们实现了滑动返回功能(滑动返回方法)
代码如下:
- (void)viewDidLoad {
[super viewDidLoad];
// 干掉系统边缘滑动手势
self.interactivePopGestureRecognizer.enabled = NO;
id target = self.interactivePopGestureRecognizer.delegate;
#pragma clang diagnostic ignored "-Wundeclared-selector"
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:target action:@selector(handleNavigationTransition:)];
// 添加手势
[self.view addGestureRecognizer:pan];
// 让导航控制器成为新加手势的代理
pan.delegate = self;
}
- 新手势添加到导航控制器的view就是全屏作用范围, 但手动对屏幕上面的导航条和下面的tabBar条起作用.因为导航条和tabBar条分别是导航控制器的另外一个view 和 tabBarController的一个view ,它们在UIWindow上显示在最外层 , 导航控制器的view 在这两者的下方. 根据事件的传递和响应链条, 导航条和tabBar条才是触发事件和响应事件的最适合view ,因此当我们在 导航条或tabBar条 滑动时, 应该是 导航条和tabBar条 响应自身事件, 所以不会有返回功能.
- 在添加自定义手势时 ,应该想干掉系统边缘滑动手势, 否则两个手势会冲突???
- 一定要让导航控制器成为手势的代理, 而不是self.interactivePopGestureRecognizer.delegate = self;
因为handleNavigationTransition:是系统的方法,不需要自己实现编译时会报警告,说方法为声明,如下:
这时可以在这个手势之前添加一行忽略警告的代码:
#pragma clang diagnostic ignored "-Wundeclared-selector"