UIPanGestureRecognizer進行檢視滑動並處理手勢衝突

KFC是做基的發表於2018-01-18

效果圖

UIPanGestureRecognizer進行檢視滑動並處理手勢衝突

詳解

概覽

頁面構成:地圖檢視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;
}
複製程式碼

結束

相關文章