美文网首页程序员iOS Developer
iOS-返回手势之无侵入性添加

iOS-返回手势之无侵入性添加

作者: 190CM | 来源:发表于2018-01-08 16:54 被阅读271次

    首先, 起因就是被要求为一个已经开发并上线的项目添加返回手势, 因为本身并不熟悉项目, 所有必须使用无侵入性的方法去实现, 实现的方案也是千千万, 只是说明一下我所使用的方法, 自认为超级简洁和方便。

    1.runtime添加手势给UIViewcontroller

    最先想到的就是利用runtime添加手势给UIViewcontroller, 而且系统自带侧滑手势的回调方法handleNavigationTransition:,我们在自己的手势上直接用它的回调方法, 大大减少了我们的代码量和复杂度。

    #import "UIViewController+popGesture.h"
    
    
    @implementation UIViewController (popGesture)
    
    + (void)load{
        [super load];
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            // 假如要打开controller的统计 ,则把下面这行代码打开
            __gbh_tracer_swizzleMethod([self class], @selector(loadView), @selector(newLoadView));
        });
    }
    
    - (void)newLoadView {
        [self newLoadView];
            
        id target = self.navigationController.interactivePopGestureRecognizer.delegate;
        
        // handleNavigationTransition:为系统私有API,即系统自带侧滑手势的回调方法,我们在自己的手势上直接用它的回调方法
        UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:target action:@selector(handleNavigationTransition:)];
        panGesture.delegate = self; // 设置手势代理,拦截手势触发
        [self.view addGestureRecognizer:panGesture];
        
        // 一定要禁止系统自带的滑动手势
        self.navigationController.interactivePopGestureRecognizer.enabled = NO;
    }
    
    
    
    // 什么时候调用,每次触发手势之前都会询问下代理方法,是否触发
    // 作用:拦截手势触发
    - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
    {
        // 当前控制器是根控制器时,不可以侧滑返回,所以不能使其触发手势
        if(self.navigationController.childViewControllers.count == 1)
        {
            return NO;
        }
        
        return YES;
    }
    
    //// 允许多个手势并发
    //- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    //    return YES;
    //}
    
    
    
    // 交换方法
    void __gbh_tracer_swizzleMethod(Class class, SEL originalSelector, SEL swizzledSelector){
        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
        
        BOOL didAddMethod =
        class_addMethod(class,
                        originalSelector,
                        method_getImplementation(swizzledMethod),
                        method_getTypeEncoding(swizzledMethod));
        
        if (didAddMethod) {
            class_replaceMethod(class,
                                swizzledSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    }
    
    @end
    

    这样就实现了界面返回,是不是很简单,不过这样只能实现UIViewController界面的返回,在拥有UITableView和UIScrollview时就失效了,这是为什么呢?
    因为我们的返回代码是加载在UIViewController上,并没有为UIScrollview添加,返回的手势并不能传递到UIViewController,所以就失效了

    2.处理滚动视图手势问题

    为了无侵入依然使用分类的方法,依然我们已经分析到原因,只需要滚动视图将我们需要的返回手势传递下去即可

    #import "UIScrollView+popGesture.h"
    
    @implementation UIScrollView (popGesture)
    
    #define IPHONE_H [UIScreen mainScreen].bounds.size.height //屏幕的高度
    #define IPHONE_W [UIScreen mainScreen].bounds.size.width // 屏幕的宽度
    
    // 手势事件会一直往下传递,不论当前层次是否对该事件进行响应。
    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
        
        if ([self panBack:gestureRecognizer]) {
            return YES;
        }
        return NO;
    }
    
    //location_X可自己定义,其代表的是滑动返回距左边的有效长度
    - (BOOL)panBack:(UIGestureRecognizer *)gestureRecognizer {
        
        //是滑动返回距左边的有效长度 左1/8有效区域
        int location_X = 0.125 * IPHONE_W;
        
        if (gestureRecognizer == self.panGestureRecognizer) {
            UIPanGestureRecognizer *pan = (UIPanGestureRecognizer *)gestureRecognizer;
            CGPoint point = [pan velocityInView:pan.view];
            UIGestureRecognizerState state = gestureRecognizer.state;
            if (UIGestureRecognizerStateBegan == state || UIGestureRecognizerStatePossible == state) {
                CGPoint location = [gestureRecognizer locationInView:self];
    
                if (point.x > 0 && location.x < location_X && self.contentOffset.x <= 0) {
                    return YES;
                }
            }
        }
        return NO;
        
    }
    
    
    - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
        
        if ([self panBack:gestureRecognizer]) {
            return NO;
        }
        return YES;
        
    }
    

    这样任何滚动视图都实现了滑动返回,是不是很简单,虽然不会写作,但是都是干货,觉得有用就给我个赞吧,你的赞就是我的动力。

    相关文章

      网友评论

        本文标题:iOS-返回手势之无侵入性添加

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