View的事件分发机制

来源:互联网 发布:mac无法验证qq邮箱 编辑:程序博客网 时间:2024/05/17 23:39
一、点击事件的传递规则
    点击事件的分发:对MotionEvent事件的分发过程,也即当一个MotionEvent产生时,系统需要将其传递给一个具体的View来处理,这个过程即为分发过程;
1.1 3个重要方法
    public boolean dispatchTouchEvent(MotionEvent ev)
    用来进行事件分发。返回结果受当前view的onTouchEvent和下级View的dispatchTouchEvent方法的影响,表示是否消费该事件。
1.1.1 事件分发何时终止
    1)return true:事件分发给当前View并由dispatchTouchEvent进行消费,同时事件会停止向下传递;
    2)return fasle:事件会分发给事件源Activity或者父级的onTouchEvent进行消费,停止分发;
    3)return super.dispatchTouchEvent,事件会自动分发给当前view的onInterceptTouchEvent方法
    public boolean onInterceptTouchEvent(MotionEvent ev)
    在上述dispatchTouchEvent方法内调用用来判断是否拦截某事件。返回结果表示是否拦截当前事件。
1.1.2 事件拦截何时终止
1)return  true:则表示事件进行拦截,并将拦截到的事件交由当前View的onTouchEvent进行处理;
    2)return false:则表示事件放行,当前View上的事件会被传递到子View中,再由子View的dispatchTouchEvent开始对事件进行分发;
    3)return super.onInterceptTouchEvent,事件默认会被拦截,并将拦截到的事件交由当前View的onTouchEvent进行处理;
public boolean onTouchEvent(MotionEvent ev)
    在dispatchTouchEvent方法内调用用来处理点击事件,返回结果表示是否消费当前事件;如果不消费,则在同一事件序列中,当前view无法再次接收到事件;
1.1.3 事件消费何时终止    
1)return true:则表示接收并消费当前事件;
    2)return false:则表示该事件会向上传递,并由上层View的onTouchEvent来接收;如果传递到上层的onTouchEvent还是返回false,说明该事件无效,而且接收不到下一次事件;
    3)return super.onTouchEvent:跟返回false相同;
这3个方法的关系如下:

    1)对于ViewGroup来说,点击事件产生后,首先会传递给它,这时它的dispatchTouchEvent方法被调用,如果这个viewgroup的onInterceptTouchEvent方法返回true表示此viewgroup要拦截当前事件,接着事件会被它的onTouchEvent处理;如果这个viewgroup的onInterceptTouchEvent方法返回false表示它不拦截当前事件,此时事件会继续传递给它的子元素处理,接着子元素的dispatchTouchEvent被调用
    2)对于view来说,如果view设置onTouchListener,那么此时onTouchListener的onTouch方法会被回调;这时事件如何处理跟onTouch方法返回值有关:如果返回false,则当前view的onTouchEvent方法被调用;如果返回true,onTouchEvent方法不会被调用---->view的onTouchListener优先级比onTouchEvent高。
    3)MotionEvent事件产生后,其传递顺序:Activity--->Window---->View;
    4)ViewGroup默认不拦截任何事件;
    5)View没有onInterceptTouchEvent方法,一旦点击事件传递给它,其onTouchEvent方法会立刻被执行;
    6)View的onTouchEvent默认都会消费该事件;
二、事件分发的源码解析
2.1 Activity对点击事件的分发过程
    当MotionEvent事件发生时,该事件最先传递给当前Activity,此时由Activity的dispatchTouchEvent进行事件分发:具体工作是由Activity内部window来完成,然后window才把事件交给DecorView来处理(最顶级view);

  1)事件开始交给window进行分发:见第二个if中的superDispatchTouchEvent方法;该方法返回true,说明事件已经消费;返回false说明事件没有消费,这时Activity的onTouchEvent方法被调用;
2.2 Window如何将事件传递给ViewGroup
    Window是抽象类,同时superDispatchTouchEvent方法也是抽象方法--->Window类的具体实现类是PhoneWindow,在PhoneWindow类中superDispatchTouchEvent具体实现了将事件传递给DecorView。源代码如下:

2.3 顶级View对点击事件的分发过程
    1)首先看ViewGroup对点击事件的分发过程:也即dispatchTouchEvent(MotionEvent ev)方法被调用,第一步查看点击事件是否被拦截;如果拦截,就自己处理;如果不拦截,就交给它的子View来消费事件;
2)viewgroup不拦截事件时,会遍历viewgroup的所有子元素,然后判断子元素是否能够接收到点击事件,标准:子元素是否在播动画和点击事件坐标是否落在子元素区域。
     如果满足这两个条件,事件会传递给它处理。
 2.4 View对点击事件的处理过程
   1)较为简单,因为其没有子元素无法向下传递事件,也即view只能消费事件;
     2)判断view有没有设置OnTouchListener,如果设置OnTouchListener而且onTouch方法返回true,此时view的onTouchEvent不会被调用,此时view的dispatchTouchEvent返回true;如果没有设置OnTouchListener以及onTouch方法返回false,view的onTouchEvent被调用。
3)onTouchEvent实现:只要View的CLICKABLE和LONG_CLICKABLE有一个为true,那么view就会消耗此事件,此时onTouchEvent方法返回true;然后在ACTION_UP事件发生时,会触发performClick方法,如果View设置OnClickListener,那么在performClick中调用onClick方法。
    
    
    
    
    
    
    
    
    
    
0 0