基于runtime(80行代码)拦截系统全屏返回手势

作者: ZhengYaWei | 来源:发表于2017-03-04 11:03 被阅读1100次

    都知道到导航栏自定义的时候,系统的全屏返回手势可能会失效。对于一个产品级的应用程序,没有了全屏返回手势,会是个很致命的缺陷。之前解决这个问题一般都是使用FDFullScreenPopGesture这个第三方,使用起来也非常简单,仅仅将文件拖到项目中就可以。其实吧,这个第三方和我这篇文章要将的东西,其实是一个原理。同样仅仅只是将文件拖动到工程中就可以实现全屏返回手势,仅仅80多行代码就可以实现。源码连接:https://github.com/ZhengYaWei1992/ZWFullScreenPanBackDemo

    在开始这篇文章之前,首先对runtime常用的几个场景必须要知道:1、使用runtime关联属性,简化代码,减少耦合。2、使用runtime的交叉方法,替换系统方法,满足自己更多的需求。3、使用runtime获取对象的属性列表,并基于KVC设置属性值,第三方模型转换一般都会使用到这点,这是字典转模型的基础。关于上述三点,之后我会写一些文章,系统的整理下,不仅仅只是说一些简单的语法问题,还会告诉大家如何在实际项目中使用。基于runtime拦截全屏返回手势,这里我们只是用到前两点,获取属性列表这一点暂时用不到。

    看一下八十多行代码如何拦截系统全屏返回手势,为所有push界面增加全屏返回手势。
    首先创建一个UINavigationController的分类(UINavigationController+ZWPanBack),然后在.h文件中借助关联对象增加一个全屏拖拽返回手势。

    @interface UINavigationController (ZWPanBack)
    // 自定义全屏拖拽返回手势
    @property (nonatomic, strong, readonly) UIPanGestureRecognizer *zw_popGestureRecognizer;
    
    @end
    

    在.m文件中我们还需要增加一个分类ZWFullScreenPopGestureRecognizerDelegate。其中gestureRecognizerShouldBegin:是手势的代理方法,这个方法我们可以控制全屏返回手势的开启和关闭。但是如何拦截到系统的全屏返回手势,并叫系统的管理权限移交到这段代码中,具体请往下看,设置runtime的另外一个知识点,交叉方法。另外,navigationController这个自定义属性同样也需要通过关联属性添加。

    @interface ZWFullScreenPopGestureRecognizerDelegate: NSObject <UIGestureRecognizerDelegate>
    @property (nonatomic, weak) UINavigationController *navigationController;
    @end
    
    @implementation ZWFullScreenPopGestureRecognizerDelegate
    //代理方法的实现
    //在这里做手势识别判断
    - (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer {
        //判断是否是根控制器,如果是直接取消手势
        if (self.navigationController.viewControllers.count <= 1) {
            return NO;
        }
        //如果正在转场动画,取消手势
        if ([[self.navigationController valueForKey:@"_isTransitioning"] boolValue]) {
            return NO;
        }
        //判断手势方向,如果是从左往右拖动才开启手势
        CGPoint translation = [gestureRecognizer translationInView:gestureRecognizer.view];
        if (translation.x <= 0) {
            return NO;
        }
        
        return YES;
    }
    @end
    

    在刚加载这个分类的时候,系统会调用load这个方法,这个方法中我们可以替换系统的方法,实现自定义方法。将系统方法的管理权限交给zw_pushViewController:animated:这个自定义方法。

    //系统方法,加载时调用
    + (void)load {
        Method originalMethod = class_getInstanceMethod([self class], @selector(pushViewController:animated:));
        Method swizzledMethod = class_getInstanceMethod([self class], @selector(zw_pushViewController:animated:));
        //系统方法和自定义方法交换
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
    
    

    zw_pushViewController:animated:这个自定义方法的实现。这个方法中我们可以寻找交互手势,如果交互手势没有被添加,就添加自定义交互手势zw_popGestureRecognizer。同时禁用系统的交互手势。

    //自定义方法和系统方法做交换
    - (void)zw_pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
        
        //寻找交互手势,如果交互手势没有被添加就添加交互手势。
        if (![self.interactivePopGestureRecognizer.view.gestureRecognizers containsObject:self.zw_popGestureRecognizer]) {
            [self.interactivePopGestureRecognizer.view addGestureRecognizer:self.zw_popGestureRecognizer];
            
            NSArray *targets = [self.interactivePopGestureRecognizer valueForKey:@"targets"];
            id internalTarget = [targets.firstObject valueForKey:@"target"];
            SEL internalAction = NSSelectorFromString(@"handleNavigationTransition:");
            
            self.zw_popGestureRecognizer.delegate = [self zw_fullScreenPopGestureRecognizerDelegate];
            [self.zw_popGestureRecognizer addTarget:internalTarget action:internalAction];
            
            // 禁用系统的交互手势
            self.interactivePopGestureRecognizer.enabled = NO;
        }
        
        if (![self.viewControllers containsObject:viewController]) {
            [self zw_pushViewController:viewController animated:animated];
        }
    }
    

    就是这些,什么第三方无非也就是如此,80行代码就可以解决的事,使用起来仅仅将这个分类添加到工程中即可,因为这是基于运行时,在运行时面前所谓的私有全是暴露的。为了大家的方便就直接附上源码链接:https://github.com/ZhengYaWei1992/ZWFullScreenPanBackDemo

    相关文章

      网友评论

      • 2ac712b8d073:又看到一篇精品文章
        ZhengYaWei:@啦啦啦德玛西亚万岁啊 很早以前写的。以前也不注意排版 感觉写的有点垃圾
      • c44c0bf3f747:这个真心是佩服了
      • butterflyer:runtime 好处多啊。
        ZhengYaWei:@butterflyer 是的啊,很多很多的
      • 449320fdbe1a:运行时确实够神奇
        ZhengYaWei:运行时有很多用处的,简化代码,交叉方法,也是字典转模型的基础

      本文标题:基于runtime(80行代码)拦截系统全屏返回手势

      本文链接:https://www.haomeiwen.com/subject/ojmdgttx.html