全屏滑动返回功能的实现

  • 思考为什么系统手势不能全屏滑动?
  • 上一节已经分析了滑动返回功能是由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"

results matching ""

    No results matching ""