view的滑动冲突

原创 2018年04月16日 16:32:07

一、常见冲突场景: 
(1)外部滑动方向和内部滑动方向不一致 
主要是将ViewPager和Fragment配合使用所组成的页面滑动效果,主流应用几乎都会使用这个效果。在这种效果中,可以通过左右滑动来切换页面,而每个页面内部往往又是一个ListView。这种情况是有滑动冲突的,但是ViewPager内部处理了这种滑动冲突,因此采用ViewPager时我们无需关注此问题。但是如果我们采用的是ScrollView等,就需要手动处理滑动冲突了,否则造成的后果就是内外两层只能有一层能够滑动,这是因为两者之间的滑动事件有冲突。此外还有其他情况,比如外部上下滑动、内部左右滑动等,但是他们属于同一类滑动冲突。 
(2)外部滑动方向和内部滑动方向一致 
当内外两层都在同一个方向可以滑动的时候,显然存在逻辑问题。因为当手指开始滑动时,系统无法知道用户到底是想让哪一层滑动,所以当手指滑动时就会出现问题,要么只有一层可以滑动,要么就是内外两层都滑动的很卡顿。在实际开发中,这种场景主要是指内外两层View同时能上下滑动或者是可以同时左右滑动。 
(3)上面两种情况嵌套 
是上面两种情况的嵌套,所以他的滑动冲突看起来更复杂了。比如:内层有一个场景一的滑动效果,然后外层又有一个场景二的滑动效果。具体说就是,外部有一个SlideMenu效果,然后内部有一个ViewPager,ViewPager的每一个页面又是一个ListView。虽说看起来更复杂,但是他是几个单一滑动冲突的叠加,因此只需要分别处理内层和中层、中层和外层之间的滑动冲突即可。

从本质上来说,这三种滑动冲突场景的复杂度其实是相同的,因为他们的区别仅仅是滑动策略的不同。解决滑动冲突的方法,基本上是运用内部拦截和外部拦截来处理的。

二、滑动冲突的解决方式 
1、外部拦截法 

外部拦截法是指点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截,如果不需要就不拦截,这样就可以解决滑动冲突的问题,这种方法比较符合点击事件的分发机制。外部拦截需要重写父容器的onInterceptTouchEvent方法,在内部做相应拦截即可。

相应的伪代码如下:

public boolean onInterceptTouchEvent(MotionEvent event){
    boolean intercepted=false;
    int x=(int)event.getX();
    int y=(int)event.getY();
    switch(event.getAction){
        case MotionEvent.ACTION_DOWM:
            intercepted=false;
        break;
        case MotionEvent.ACTION_MOVE:
          if(父容器需要当前点击事件){
              intercepted=true;
          }else{
              intercepted=false;
          }
        break;
        case MotionEvent.ACTION_UP:
            intercepted=false;
        break;
    }
    mLastXIntercept=x;
    mLastYIntercept=y;
    return intercepted;
}

上述代码是外部拦截法的典型逻辑,针对不同的滑动冲突,只需要修改父容器需要当前点击事件这个条件即可,其他均不做修改。 
在onIntercepetTouchEvent方法中: 
(1)ACTION_DOWN事件,父容器必须返回false,即不拦截ACTION_DOWN事件,这是因为一旦拦截ACTION_DOWN事件,那么后续的ACTION_MOVE和ACTION_UP事件都会直接交由父容器处理,这个时候事件就没法再传递给子元素了; 
(2)ACTION_MOVE事件,这个事件可以根据需求来决定是否拦截,如果父容器需要拦截则返回true,否则但会false; 
(3)ACTION_UP事件,这里必须返回false,因为ACTION_UP事件本身就没有太多意义。

假设事件交由子元素处理,如果父容器在ACTION_UP时返回了true,就会导致子元素无法接受到ACTION_UP事件,这个时候子元素的onClick事件就无法触发,但是父容器比较特殊,一旦它开始拦截任何一个事件,那么后续的事件都会交给它来处理,而ACTION_UP作为最后一个事件也必行可以传递给父容器,即便父容器的onInterceptTouchEvent方法在ACTIPN_UP是返回了false。

2、内部拦截法 
内部拦截法是指父容器不拦截任何事件,所有的事件都传递给子元素,如果子元素需要就直接消耗掉,否则就交由父容器进行处理,这种方法和Android中的事件分发机制不一致,需要配合requestDisallowInterceptTouchEvent方法才能正常工作,使用起来较外部拦截稍显复杂。需要重写子元素的dispatchTouchEvent方法,

需要重写子元素的dispatchTouchEvent方法,伪代码如下:

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 daltaY=y-mLastY;
            if(父容器需要此类点击事件){
                parent.requestDisallowInterceptTouchEvent(false);
            }
            break;

       case MotionEvent.ACTION_UP:
           break;
    }
    mLastX=x;
    mLastY=y;
    return super.dispatchTouchEvent(event);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

当面对不同的滑动策略时只需要修改里面的条件即可,其他不需要做改动。除了子元素需要做处理以外,父元素也需要默认拦截除了ACTION_DOWN以外的其他事件,这样当子元素调用parent.requestDisallowInterceptTouchEvent(false)方法时,父元素才能继续拦截所需的事件。

因为ACTION_DOWN事件并不受FLAG_DISALLOW_INTERCEPT这个标记位的控制,所以父容器一旦拦截ACTION_DOWN事件,那么所有的事件都无法传递到子元素中去,这样内部拦截就无法起作用了。所以父元素需做如下修改:

public boolean onInterceptTouchEvent(MotionEvent event){

    int action=event.getAction();
    if(action==MotionEvent.ACTION_DOWN){
     return false;
    }else{
     return true;
      }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

以上两种方式,基本可以完美解决开发中遇到的滑动冲突问题。


一文解决Android View滑动冲突

上一篇文章我们讲述了Android View事件分发机制。如果你对View的事件分发还不熟悉,建议先去看一下 一文读懂Android View事件分发机制 它是我们今天滑动冲突解决的理论基础! 如果...
  • u010302764
  • u010302764
  • 2017-05-27 09:57:06
  • 3241

滑动冲突处理示例代码

  • 2016年07月24日 14:25
  • 563KB
  • 下载

一个Demo带你彻底掌握View的滑动冲突

本文已授权微信公众号:鸿洋(hongyangAndroid)在微信公众号平台原创首发。 最近在重新学习Android自定义View这一块的内容,遇到了平时开发中经常碰到的一个棘手问题:View的滑动冲...
  • tyk0910
  • tyk0910
  • 2016-11-30 22:40:36
  • 6540

View的滑动冲突解决方案

1.常见的滑动冲突场景1.1 外部滑动方向和内部滑动的方向不一致这种情况我们经常遇见,比如使用viewpaper+listview时,在这种效果中,可以通过左右滑动切换页面,而每一个页面往往又是一个l...
  • u014316462
  • u014316462
  • 2016-07-24 16:09:08
  • 2064

Android中View的滑动冲突——Android开发艺术探索笔记

相信开发Android的人都会有这种体会:从网上下载的demo运行的好好的,但是只要出现了滑动冲突,Demo就无法正常工作了。但是不用担心,解决滑动冲突有固定的模式,常见的有内部拦截和外部拦截两种,只...
  • L664675249
  • L664675249
  • 2016-02-29 16:50:07
  • 2186

android 解决View的滑动冲突:滑动方向不一致的滑动

  • 2016年03月03日 15:19
  • 7.01MB
  • 下载

通俗理解Android中View的事件分发机制及滑动冲突处理

说起Android滑动冲突,是个很常见的场景,比如SliddingMenu与ListView的嵌套,要解决滑动冲突,不得不提及到View的事件分发机制。 一、Touch事件传递规则分析 首先,我们要...
  • yyh352091626
  • yyh352091626
  • 2016-02-25 13:47:40
  • 12572

Android 笔记 ViewPager的滑动与子view内部滑动事件的冲突问题

ViewPager 与子view的滑动冲突在上一次笔记中建设了一个可以滑动的photoView,显示图片,可以放大,滑动大部分时候这个自定义View会和ViewPager一起使用。也就是我们通常看到...
  • super_zq
  • super_zq
  • 2016-10-13 14:14:43
  • 1718

四种方法解决ScrollView嵌套listview的滑动冲突问题

在工作中,曾碰到过多次scrollView嵌套listview的问题,网上的解决办法很多,但大都是杂而不全,在这里,我从使用scrollview嵌套listview结构的原因、这个结构碰到的问题、几种...
  • csuhanshuai
  • csuhanshuai
  • 2016-03-11 16:34:05
  • 715

Android技术之View的事件分发机制和滑动冲突解决方案

本文转载:http://mp.weixin.qq.com/s/fhr3u2iA-R8J4WdRtMqWGAReact-Native学习指南,汇集React-Native各类学习资源,给大家提供便利,并...
  • wanghonghuai
  • wanghonghuai
  • 2017-02-17 10:57:51
  • 1130
收藏助手
不良信息举报
您举报文章:view的滑动冲突
举报原因:
原因补充:

(最多只允许输入30个字)