当咱们手指按下时,Android采用层层传递-冒泡的方式处理点击事件。例如,如今公司来了个小项目,老板一看分配给经理作,经理一看分配给小组长,小组长一看好简单,分配给组员。若是在这个传递过程当中(也就是还为分配到最底部时),某一层以为我来负责这个比较好的话就会拦截掉这个消息,而后把它处理了,下面的就收不到有消息的这个通知。若是一直到了底层的话,组员若是能完成,就完成它。若是不能完成,那么就报告给组长,说组长我作不来,边学边作要影响进度。组长一看我也作不来,就给经理,经理一看我也不会,就给老板。这样也就一层层的传递了。
以上的意思也即:消息从上到下依次传递,若是在传递的过程当中被拦截了就中止下传。若是没有被拦截,就一直传递到底部,若是底部不可以消耗该消息,那么就又一层层的返回来,返给上层,直到被消耗或者是到达最顶层。在此过程当中,存在三个重要的方法:spa
dispathTouchEvent(MotionEvent ev)
负责事件的分发,它的返回值就是表示是否消耗当前事件;
onInterceptTouchEvent(MotionEvent ev)
用于判断是否拦截该消息,若是当前View拦截了某个时间,那么在同一个事件序列中,此方法不会被再次调用。返回结果表示是否拦截当前事件 。
onTouchEvent(MotionEvent ev)
处理事件。返回结果表示是否消耗当前事件,若是不消耗,则在同一时间序列中,当前View没法再次接收到事件。
对于一个根ViewGroup来讲,点击事件产生后,首先会传递给它,并调用它的dispath方法。若是这个ViewGroup的onIntercept方法返回true就表示它要拦截当前事件,false就表示不拦截,这个时候事件就会继续传递给子元素,接着调用子元素的dispath方法,一直重复以上过程到事件被处理。code
下面介绍一下常见的问题及解决方法:blog
1、滑动冲突事件
View的滑动冲突产生愿意大概能够分为三种:io
好比说一个常见的,外部一个ListView,里面一个ScrollView,滑动时出现冲突?event
此时通常是采用外部拦截法(即结合onInterceptTouchEvent、onTouchEvent)来进行解决。具体方法以下:class
(1)外部拦截法容器
外部拦截法就是指全部的点击时间都通过父容器的拦截处理,若是父容器须要此事件就拦截,若是不须要此事件就不拦截。经过重写父容器的onInterceptTouchEvent方法:List
case MotionEvent.ACTION_DOWN: intercepted = false; break; case MotionEvent.ACTION_MOVE: if(父类容器须要) { intercepted = true; } else { intercepted = false; } break; case MotionEvent.ACTION_UP: intercepted = false; break; return intercepted;
注:ACTION_DOWN事件父类容器就必须返回false,由于若是父类容器拦截了的话,后面的Move等全部事件都会直接由父类容器处理,就没法传给子元素了。UP事件也要返回false,由于它自己来讲没有太多的意义,可是对于子元素就不一样了,若是拦截了,那么子元素的onClick事件就没法触发。request
内部拦截法
这种方法指的是父容器不拦截任什么时候间,全部的事件都传递给子元素,若是子元素须要此事件就直接消耗掉,不然就交给父容器进行处理。它须要配合requestDisallowInterceptTouchEvent方法才能正常工做。咱们须要重写子元素的dispatch方法。
case MotionEvent.ACTION_DOWN: parent.requestDisallowInterceptTouchEvent(true); break; MotionEvent.ACTION_MOVE: if(父容器须要此类点击事件) { parent.requestDisallowInterceptTouchEvent(false); } break; return super.dispatchTouchEvent(event);
这种方法的话父类容器须要默认拦截除了ACTION_DOWN之外的其余时间,这样当子元素调用request方法的时候父元素才能继续拦截所需的事件。
其余的
若是以为上面两个方式太复杂,看晕了,其实也能够本身根据项目的实际须要来指定本身的策略实现。例如根据你手指按的点的位置来判断你当前触碰的是哪一个控件,以此来猜想用户是不是要对这个控件进行操做。若是点击的是空白的地方,就操做外部控件便可。
,具体可参考ViewPager中的滑动冲突