解決右滑返回手勢和UIScrollView中的手勢衝突

weixin_33912445發表於2016-11-17

首先說一下我們專案是怎麼簡單解決的

@interface BaseNav : UINavigationController
- (void)viewDidLoad
{
    [super viewDidLoad];
    self.navigationBar.hidden = YES;
    
    
}

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if (self.viewControllers.count >= 1)
    {
        viewController.hidesBottomBarWhenPushed = YES;
    }
    [super pushViewController:viewController animated:animated];
    self.interactivePopGestureRecognizer.delegate = self;
}

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    BOOL ok = YES; // 預設為支援右滑反回
    if ([self.topViewController isKindOfClass:[XTYBaseWebViewController class] ]|| [self.topViewController isKindOfClass:[GenericWebViewController class] ]||[self.topViewController isKindOfClass:[TempActViewController class] ]) {
        ok = NO;
    }
    return ok;
}

當讓這可能不是最好的解決方案 於是又是在網上各種查
出現的原因

iOS系統中,滑動返回手勢,其實是一個UIPanGestureRecognizer,系統預設的操作是隻有滑動螢幕的左邊的某個位置,UIPanGestureRecognizer才會起作用。UIScrollView的滑動手勢也是UIPanGestureRecognizer。UIGestureRecognizer和UIView是多對一的關係(具體點這裡),UIGestureRecognizer一定要和view進行繫結才能發揮作用。因此不難想象,UIGestureRecognizer對於螢幕上的手勢事件,其接收順序和UIView的層次結構是一致的

UINavigationController.view —>  UIViewController.view —>  UIScrollView —>  Screen and User's finger

即UIScrollView的panGestureRecognizer先接收到了手勢事件,直接就地處理而沒有往下傳遞。

實際上這就是兩個panGestureRecognizer共存的問題。

解決方案一

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    
    if ([self panBack:gestureRecognizer]) {
        return NO;
    }
    return YES;
    
}
- (BOOL)panBack:(UIGestureRecognizer *)gestureRecognizer {
    
    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];
            if (point.x > 0 && location.x < 20 && self.contentOffset.x <= 0) {
                return YES;
            }
        }
    }
    return NO;
    
}

解決方案二

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    // 首先判斷otherGestureRecognizer是不是系統pop手勢
    if ([otherGestureRecognizer.view isKindOfClass:NSClassFromString(@"UILayoutContainerView")]) {
        // 再判斷系統手勢的state是began還是fail,同時判斷scrollView的位置是不是正好在最左邊
        if (otherGestureRecognizer.state == UIGestureRecognizerStateBegan && self.contentOffset.x == 0) {
            return YES;
        }
    }
    
    return NO;
}

原理:
scrollView的pan手勢會讓系統的pan手勢失效,所以我們只需要在系統手勢失效且scrollView的位置在初始位置的時候讓兩個手勢同時啟用就可以了。

下面一個 git 連線 運動 runtime 來做的側滑返回

https://github.com/W-King/PPX_LateralSpreads

相關文章