UIPanGestureRecognizer进行视图滑动并处理手势冲突

7,794 阅读2分钟

效果图

详解

概览

页面构成:地图视图mapVC , 资源信息视图soureVC(视图控制器的view上放了一个UITableView)。
动画效果: 1. 上滑:soureVC通过滑动慢慢上移,到达上边界限后,再滑动就只是滑动tableview 2. 下滑:只有当tableview滑动到头后,才会滑动soureVC向下。

分析

  1. 首先我们肯定是给sourceVC的view上添加平移手势 UIPanGestureRecognizer
  2. 手势的实现方法中根据 Pan手势的三种状态 进行sourceVC的view的origin的处理
首先介绍一下 几个 方法:
translationInView : 手指在视图上移动的位置(x,y)向下和向右为正,向上和向左为负。
locationInView : 手指在视图上的位置(x,y)就是手指在视图本身坐标系的位置。
velocityInView: 手指在视图上移动的速度(x,y), 正负也是代表方向,值得一提的是在绝对值上|x| > |y| 水平移动, |y|>|x| 竖直移动。

- (void)panGestureRecognized:(UIPanGestureRecognizer *)recognizer{
    
    CGPoint point = [recognizer translationInView:self.view];
    // 1.手势开始时:记录 sourceVC.view 原始的 origin , 必须作为属性记录,移动过程才能顺畅,不然卡顿
    if (recognizer.state == UIGestureRecognizerStateBegan) {
        self.containerOrigin = recognizer.view.frame.origin;
    }
    // 2.手势移动过程中: 在边界处做判断,其他位置
    if (recognizer.state == UIGestureRecognizerStateChanged) {
        
        CGRect frame = recognizer.view.frame;
        frame.origin.y = self.containerOrigin.y + point.y;
        
        if (frame.origin.y < 192) { // 上边界
            frame.origin.y = 192;
        }
        
        if (frame.origin.y > SCREEN_HEIGHT - STATUSANDNAVIGATIONBAR_HEIGHT - 194) { // 下边界
            frame.origin.y = SCREEN_HEIGHT - STATUSANDNAVIGATIONBAR_HEIGHT - 194;
        }
        
        recognizer.view.frame = frame;
    }
    // 3.手势结束后:有向上趋势,视图直接滑动至上边界, 向下趋势,视图直接滑动至到下边界
    if (recognizer.state == UIGestureRecognizerStateEnded){
                
        if ([recognizer velocityInView:self.view].y < 0) {
            NSLog(@"向上");
            [UIView animateWithDuration:0.20 animations:^{
                CGRect frame = recognizer.view.frame;
                frame.origin.y = 192;
                recognizer.view.frame = frame;
            } completion:^(BOOL finished) {
                self.sourceVC.tableView.contentOffset = CGPointMake(0, 0);
                self.sourceVC.tableView.scrollEnabled = YES;
            }];
            
        } else {
            NSLog(@"向下");
            [UIView animateWithDuration:0.20 animations:^{
                CGRect frame = recognizer.view.frame;
                frame.origin.y = SCREEN_HEIGHT - STATUSANDNAVIGATIONBAR_HEIGHT - 194;
                recognizer.view.frame = frame;
            } completion:^(BOOL finished) {
                self.sourceVC.tableView.contentOffset = CGPointMake(0, 0);
                self.sourceVC.tableView.scrollEnabled = NO;
            }];
        }
    }
}
  1. 由于我们的sourceVC上存在tableview, 所以会导致tableview的滑动和pan滑动的 手势冲突 , 这也是为什么在上滑动过程中我屏蔽掉了tableview的scrollEnabled。但是当我们sourceVC滑动到上边界后,我们解开了tableview的滑动scrollEnabled,此时上滑是没有问题的(由于存在上边界), 但是下滑就有问题了,tableview的滑动手势和我们自定义的Pan手势冲突了,滑动tableview结果带着sourceVC的view一起向下滑了,明显不符合效果。所以需要如下处理:
// 实现UIGestureRecognizerDelegate代理方法  ,  返回YES表示支持多个手势同时触发,否则不允许多个手势同时触发
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
    
    if ([otherGestureRecognizer.view isKindOfClass:[UITableView class]]) {
        UITableView *tab = (UITableView *)[otherGestureRecognizer view];
        CGPoint vel = [tab.panGestureRecognizer velocityInView:tab];
        if (vel.y > 0) {
            // 下拉 , 只有当contentOffset.y为0时才允许多手势同时触发
            CGPoint Point= tab.contentOffset;
            return Point.y == 0;
            
        }else{
            // 上拉
            return NO;
        }
    }
    return NO;
}

结束