自定义View滑动冲突

标签: Android基础学习  android

自定义View滑动冲突

滑动冲突解决方法其实比较固定。

滑动冲突的种类

有三种发生的场景:
在这里插入图片描述

  • 场景1——外部滑动方向和内部滑动方向不一致
  • 场景2——外部滑动方向和内部滑动方向不一致
  • 场景3——上面两种情况的嵌套

处理规则

  • 滑动路径和水平形成的夹角
  • 水平方向和垂直方向的距离差距
  • 某些特殊情况可根据水平和垂直方向的速度差

解决方法

针对第一种场景

有两种方法:外部拦截,内部拦截

外部拦截

当外部上下滑动,内部左右滑动,我们先让外部拦截,当滑动是上下的时候,将事件拦截下来,如果是左右,就传递给内部。那么如何判断上下滑动还是左右滑动。

  • 滑动路径和水平形成的夹角
  • 水平方向和垂直方向的距离差距
  • 某些特殊情况可根据水平和垂直方向的速度差

重写父元素
在这里插入图片描述
在这里插入图片描述
上面是《Android开发艺术探索》里给的伪代码,是一个比较典型的逻辑。
首先,在onInterceptTouchEvent方法中,父容器一定不能拦截ACTION_DOWN,否则,后续的MOVE,UP事件都会交给父容器。其次是ACTION_MOVE事件,我们根据需求来决定父容器是否拦截,如果拦截则返回true,否则返回false。

内部拦截

内部拦截和外部拦截恰好相反,先把所有时间传给子元素,如果子元素需要则直接消耗,否则才交给父容器进行处理。子元素调用requestDisallowInterceptTouchEvent,父元素就去拦截除了down之外的所有事件(不能拦截down,否则子View什么也得不到)。
重写子元素

@Override
      public boolean dispatchTouchEvent(MotionEvent event) {
          int x = (int) event.getX();
          int y = (int) event.getY();
  
        switch (event.getAction()) {
        	case MotionEvent.ACTION_DOWN: {
              parent.requestDisallowInterceptTouchEvent(true);
              break;
         }
        case MotionEvent.ACTION_MOVE: {
             int deltaX = x - mLastX;
             int deltaY = y - mLastY;
             if (父容器需要此类点击事件) {
                 parent.requestDisallowInterceptTouchEvent(false);
             }
             break;
         }
        case MotionEvent.ACTION_UP: {
             break;
         }
         default:
             break;
         }
 
         mLastX = x;
         mLastY = y;
         return super.dispatchTouchEvent(event);
     }

requestDisallowInterceptTouchEvent() 这个方法就是告诉父类不要拦截该控件的触摸事件。
我们还需要重写父元素的onInterceptTouchEvent方法,目的是为了让父元素不拦截ACTION_DOWN事件。

 @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
 
         int action = event.getAction();
         if (action == MotionEvent.ACTION_DOWN) {
             return false;
         } else {
             return true;
         }
     }

针对第二种情景

这种场景要比上面一种复杂一些,因为滑动方向一致,所以无法通过上述的方式来判断将事件交给谁处理。在这种情况下,往往需要根据业务的需要来判定谁来处理事件。比如竖直方向的ScrollView嵌套ListView的场景下,手指在ListView上上下滑动时:当ListView滑动到顶部且手势向下时,显然ListView不能再向下滑动了,这种情况下事件需要被外层控件拦截,由ScrollView来消费;当ListView滑动到底部且手势向上时,显然ListView也不能再向上滑动了,这种情况下事件也需要被外层控件拦截,由ScrollView来消费;其它情况下,ScrollView就不能再拦截了,滑动事件就需要由ListView来消费了,即此时上下滑动时,滑动的是ListView,而不是ScrollView。后面会以这为案例进行编码实现。

详见:https://www.cnblogs.com/andy-songwei/p/11076612.html
版权声明:本文为qq_43556200原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_43556200/article/details/108201527