参考资料:

View事件分发:http://blog.csdn.net/pi9nc/article/details/9281829

ViewGroup事件分发:http://blog.csdn.net/guolin_blog/article/details/9153747

 

1      概述

Android中的布局是按树形结构层级排列的,根布局往往是一个ViewGroup,如LinearLayout,其中包裹一些子View或子ViewGroup,子ViewGroup中又包裹着它的子View或子ViewGroup,依此类推。

 

每当触摸了屏幕上的一个“东西”,都会触发这个“东西”的dispatchTouchEvent()方法,负责事件的分发。这个方法是从它的父类View或ViewGroup中继承来的。

 

因此,我们想要了解Android中的事件分发机制,就需要分别了解View的事件分发机制和ViewGroup的事件分发机制。

 

2      View事件分发

一般地,我们给一个控件添加事件,通常会调用setOnTouchListener()和setOnClickListener()这两个方法,前者是为了监听手指的按下、抬起、滑动等细节操作,而后者只是为了监听点击控件的操作。从上面的概述可以知道,无论是哪种操作,都是通过dispatchTouchEvent()方法来分配的。

 

在View类的dispatchTouchEvent()方法中,先判断这个View是否注册了OnTouchListener监听器,如果注册了,则回调其中的onTouch()方法;如果没有注册,则调用View类中的onTouchEvent()方法。

 

OnTouchListener中的onTouch()方法是回调给程序员编写的,这个方法有一个布尔类型的返回值,如果返回true则终止本次事件的分发,否则依然会调用View类中的onTouchEvent()方法。对应的部分源码如下:

if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED                  && li.mOnTouchListener.onTouch(this, event)) {    result = true;}if (!result && onTouchEvent(event)) {    result = true;}

在View类的onTouchEvent()方法中判断这个View是否是可点击的(clickable),如果是则判断这个View是否注册了OnClickListener,如果注册了就调用其中的onClick()方法。对应的部分源码如下:
   
public boolean onTouchEvent(MotionEvent event) {    if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)                          || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {        performClick();        return true;    }    return false;}public void performClick() {    if (li != null && li.mOnClickListener != null) {        li.mOnClickListener.onClick(this);    }}
从上面的代码中可以看出,如果一个控件时clickable的,那么onTouchEvent()就一定会返回true,否则返回false。

 

因此,当我们为一个控件同时设置了setOnTouchListener()和setOnClickListener()这两个方法时,会先回调OnTouchListener中的onTouch()事件,当onTouch()返回true时,才会再回调OnClickListener中的onClick()事件。

 

这里还需要注意的一点是,给一个控件设置了touch事件后,每次点击它时,都会触发一系列的ACTION_DOWN、ACTION_MOVE和ACTION_UP等事件。在此过程中,如果某一个ACTION返回了false,那么后面的一系列ACTION就不会再执行了。简单的说,当dispatchTouchEvent()在进行事件分发的时候,只有前一个ACTION返回true,才会触发后一个ACTION。

 

3      ViewGroup事件分发

当一个事件到达一个ViewGroup的时候,会递归的在它的树级结构中查找这个事件的处理者:依次遍历这个ViewGroup中的所有子View和子ViewGroup,调用它们的dispatchTouchEvent()方法,如果判断可以处理这个事件则返回true,否则返回false;当一个ViewGroup中的所有子View和子ViewGroup的dispatchTouchEvent()方法都返回false,则这个ViewGroup的dispatchTouchEvent()也返回false。

 

ViewGroup中有一个方法叫做onInterceptTouchEvent(),它标识这个ViewGroup是否要拦截其下的View的事件,默认返回的是false,表示不拦截。我们可以通过在自定义ViewGroup中重写这个方法设置其返回值为true,或者通过requestDisallowInterceptTouchEvent()方法获取拦截权限。

 

当ViewGroup的onInterceptTouchEvent()方法返回true时,所有属于这个ViewGroup中某个View的事件都会被这个ViewGroup拦截,即这个ViewGroup就成为了这个事件的处理者来处理这个事件。

 

4      综述

每当触摸了一次屏幕,根布局(ViewGroup)就会发出一次递归搜索,在其下层的布局或控件树中寻找拦截这次事件的控件,如果有控件或布局对这次事件进行了拦截,则表示这个控件或布局就是这次事件的处理者。

 

无论最终获取这个事件处理权的是View还是ViewGroup(以下统称为控件),都调用它的dispatchTouchEvent()方法对事件进行处理。

 

总之,Android中的事件分发机制的流程图如下图所示:

【Android - 进阶】之事件分发机制_第1张图片

 

更多相关文章

  1. Android事件分发机制完全解析(终极版二)
  2. Android事件分发机制和一些疑问
  3. Android设置任何控件透明度
  4. Android 控件及其属性2
  5. Android查询:模拟键盘鼠标事件(adb shell 实现)
  6. Android VideoView设置静音,Android 设置VideoView静音,Android
  7. Android Touch 事件的分发和消费机制
  8. ListView去掉分割线的几种方法
  9. Android 布局中如何使控件居中

随机推荐

  1. android 分享到微博
  2. Android适配之适配不同的系统版本
  3. android app 示例 SQLiteOpenHelper 实现
  4. Invoke-customs are only supported star
  5. 深入浅析Android消息机制
  6. 9. android Gallery(画廊)以及BaseAdapte
  7. android app内存使用限制
  8. 为什么Android的AsyncTask不适合执行长时
  9. Android实现拨打电话功能
  10. Android(安卓)Service Messenger & AIDL