iOS 側滑返回手勢與Scrollview衝突的解決辦法

weixin_34120274發表於2017-06-15

蘋果在iOS7.0以後推出了一個側滑返回手勢,當導航欄Push到下一頁時,可以通過側滑手勢pop到上一頁,這大大提高了使用者的體驗度,同時增加了可玩性。
然而有些時候,當你push到另一個介面後,如果該介面有Scrollview或繼承於Scrollview(tableview,collectionview)的控制元件,這時你可能會發現返回手勢失效了,這個是為什麼喃?
經過我多番驗證,原來是這個控制元件攔截了手勢,也就是說引起了衝突,把我的手勢佔為己有了。當然,這個對app本身沒什麼影響,但是對於有強迫症的我還是逼迫自己去找解決辦法,因為使用者體驗很重要!!

大概思路就是,既然你攔截了我的手勢,那我就要想辦法讓手勢傳遞下去,不被你攔截,所以最後的解決辦法就是對Scrollview加個Category,重寫它代理的方法,讓手勢能夠傳遞下去
  • 第一步,新建一個Scrollview的CateGory
4421183-982b4252e4a1675b.png
2B2A854A-DC2B-473F-8B56-FE40AE008A4F.png
  • 第二步,重寫這個方法,讓手勢能夠傳遞下去
4421183-b1a72c9e9c60b74a.png
0C94D23F-A7F9-4ED7-AE89-B2DDC2DAE8B1.png

-第三步,就是對手勢進行自定義,可以根據需求設定(可以設定側滑手勢的有效範圍)

4421183-fd2617372c146470.png
00154AED-3942-41BC-80B4-D00C2755130A.png

-最後你就會見證神奇的一刻了。

最後附上程式碼:

#define IPHONE_H [UIScreen mainScreen].bounds.size.height //螢幕的高度
#define IPHONE_W [UIScreen mainScreen].bounds.size.width // 螢幕的寬度
//是否支援多手勢觸發,返回YES,則可以多個手勢一起觸發方法,返回NO則為互斥.
//是否允許多個手勢識別器共同識別,一個控制元件的手勢識別後是否阻斷手勢識別繼續向下傳播,預設返回NO;如果為YES,響應者鏈上層物件觸發手勢識別後,如果下層物件也新增了手勢併成功識別也會繼續執行,否則上層物件識別後則不再繼續傳播
//一句話總結就是此方法返回YES時,手勢事件會一直往下傳遞,不論當前層次是否對該事件進行響應。
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    
    if ([self panBack:gestureRecognizer]) {
        return YES;
    }
    return NO;
    
}

//location_X可自己定義,其代表的是滑動返回距左邊的有效長度
- (BOOL)panBack:(UIGestureRecognizer *)gestureRecognizer {
    
    //是滑動返回距左邊的有效長度
    int location_X =0.15*IPHONE_W;
    
    if (gestureRecognizer ==self.panGestureRecognizer) {
        UIPanGestureRecognizer *pan = (UIPanGestureRecognizer *)gestureRecognizer;
        CGPoint point = [pan translationInView:self];
        UIGestureRecognizerState state = gestureRecognizer.state;
        if (UIGestureRecognizerStateBegan == state ||UIGestureRecognizerStatePossible == state) {
            CGPoint location = [gestureRecognizer locationInView:self];
            
            //這是允許每張圖片都可實現滑動返回
            int temp1 = location.x;
            int temp2 =IPHONE_W;
            NSInteger XX = temp1 % temp2;
            if (point.x >0 && XX < location_X) {
                return YES;
            }
            //下面的是隻允許在第一張時滑動返回生效
            //            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;
    
}

附上最後效果圖

4421183-a7cd0bdafc52f664.gif
11111111.gif

最近發現一個更暴力的方法,只需要在當前控制器加上幾行程式碼就能解決這個問題

直接上程式碼
   NSArray *gestureArray = self.navigationController.view.gestureRecognizers;
    
    for (UIGestureRecognizer *gestureRecognizer in gestureArray) {
        
        if ([gestureRecognizer isKindOfClass:[UIScreenEdgePanGestureRecognizer class]]) {
            
            [self.scrollView.panGestureRecognizer requireGestureRecognizerToFail:gestureRecognizer];
            
        }
        
    }

相關文章