美文网首页iOS_UIkitios UI与自定义控件iOS学习专题
解决右滑返回手势和UIScrollView中的手势冲突

解决右滑返回手势和UIScrollView中的手势冲突

作者: 城市之光 | 来源:发表于2016-03-01 08:44 被阅读10252次

    项目中遇到一个页面中是以一个scrollview横向Tab展示两个不同功能的显示,譬如消息和公告功能,但是由于滑动返回手势和scrollview的滑动返回手势冲突了,导致页面不再能够滑动返回。类似的还有图片浏览功能也出现过。

    iOS系统中,滑动返回手势,其实是一个UIPanGestureRecognizer,系统默认的操作是只有滑动屏幕的左边的某个位置,UIPanGestureRecognizer才会起作用。UIScrollView的滑动手势也是UIPanGestureRecognizer。那在侧边滑动时,让UIScrollView的不响应事件就OK了嘛,首先想到了继承UIScrollView 重写下面的方法,让滑动侧边时scrollView不响应事件,根据响应者链,事件最终会传递给下方的滑动手势。

    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event     {
          if (point.x < location.x) { // location.x为系统的某个点的x
              return nil;
          } else {
              return [super hitTest:point withEvent:event];
          }
    }
    

    但是,这样有个问题,就是在一个页面不同tab时,也需要滑动切换,滑动返回。

    由于scrollView的滑动手势拦截了事件,那我重写scrollView中panGestureRecognizer的代理方法,让它不拦截就好了嘛。于是继承UIScrollView,重写下面的方法。

    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    
            if ([self panBack:gestureRecognizer]) {
                 return YES;
            }
            return NO;
    
     }
    
    
    - (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 < “这个自己设定" && self.contentOffset.x <= 0) {
                       return YES;
                  }
              }
         }
         return NO;
    
    }
    

    需要侧边滑动时 panBack 返回YES,这时候,我让scrollView的手势和页面的滑动返回手势共存,scrollView不拦截手势,那不就可以滑动返回了吗。好了,测试一下,可以滑动返回,但是滑动返回时,为什么scrollView也跟着在滑动呢,太影响美观了,看来还需要另外的办法,我又回到了第一种办法时的想法,让scrollView切换的时候相应panGesture,滑动返回的时候不响应,那重写scrollView中的另外一个panGestureRecognizer的代理方法。

    - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
    
        if ([self panBack:gestureRecognizer]) {
            return NO;
        }
        return YES;
    
    }
    

    第二种方法:

     -(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;  
    }  
    

    以上的代码都是在一个自定义的UIScrollView上的,重写上面的方法即可。然后让横向滚动的scrollView继承这个自定义UIScrollView就OK了。

    原理:
    scrollView的pan手势会让系统的pan手势失效,所以我们只需要在系统手势失效且scrollView的位置在初始位置的时候让两个手势同时启用就可以了。

    相关文章

      网友评论

      • 鬼谷门生:你好 我用了你的方法 手势冲突时解决了 比如x = 20, 那么右滑的时候20以内只响应pan 但是好像上下滑动的时候每个区域都会响应pan手势呢
        城市之光:@鬼谷门生 可以判断方向吧
      • 鬼谷门生:类似网易新闻页面可以做到吗,就是所有的中空子控制器的view都是添加到scrollView上的,view是要滑动到对应的子控制器才会显示的,这时候给每个view都要添加一个侧滑手势,但是侧滑手势会覆盖scrollView的滚动,底部的scrollView用这个可以实现吗,就是滚动scrollView的时候pan不响应,侧滑pan的时候scrollView滑动不响应

        城市之光:@洁简 有个location.x就是判断偏移量的
        洁简:@城市之光 怎么判断左边边界呢
        城市之光:这个判断是否滑到左边边界来开启对应的手势了
      • Rooses兵:感谢楼主的解决方法,我的问题已解决.我是建立UIScrollview的分类,并重写楼主的
        - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
        和- (BOOL)panBack:(UIGestureRecognizer *)gestureRecognizer 这两个方法,就可以啦
        城市之光:@zl_xust 自己想吧,已经说的很清楚了,如果是喜欢技术的话这点是难不倒你的
        zl_xust:用分类怎样处理呢,求解
        城市之光:@Rooses兵 不客气,用分类是好点
      • LV大树:有demo吗?楼主。
      • lunaSun:其实一句话就可以解决的。。只要右滑返回手势优先就好了,
        mainScrollView.panGestureRecognizer.requireGestureRecognizerToFail(navigationController!.interactivePopGestureRecognizer!)
        城市之光:试过了吗?
        MindTheGap:@城市之光 这并不是一行正确的代码。😓
        城市之光:@lunaSun是的,谢谢!
      • cb3fc6332154:重写”shouldRecognizeSimultaneouslyWithGestureRecognizer“不明智!因为这个在UIScrollView中根本没有被暴露出来。而这个方法处理的情况在你考虑的范围之外时,你默认返回no,实际系统原来打算返回什么你根本不知道,这就很危险了。
        城市之光:@弗丁老爹 你可以实现手势的代理方法嘛
        cb3fc6332154:你没懂我说的,没在uiscrollview中暴露。uiscrollview本身实现这个代理的逻辑你根本不知道。
        城市之光:@弗丁老爹 你确定没暴露吗?// called when the recognition of one of gestureRecognizer or otherGestureRecognizer would be blocked by the other
        // return YES to allow both to recognize simultaneously. the default implementation returns NO (by default no two gestures can be recognized simultaneously)
        //
        // note: returning YES is guaranteed to allow simultaneous recognition. returning NO is not guaranteed to prevent simultaneous recognition, as the other gesture's delegate may return YES
        - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
      • 超_iOS:scrollview 做图片浏览时只有一张图片怎么取消屏幕滑动返回功能啊
        城市之光:@小菜超 把系统的滑动手势设置为nil就行了吧
        超_iOS:@小菜超 系统的,
        城市之光:@小菜超 不知道你用系统的右滑返回还是自定义的呢,可以根据scrollView的子视图的个数来判断吧

      本文标题:解决右滑返回手势和UIScrollView中的手势冲突

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