Android事件分发机制

  • 一、被分发的对象
  • 二、分发事件的组件
  • 三、分发的核心方法
  • 四、事件分发过程
  • Activity的dispatchTouchEvent方法
  • ViewGroup的dispatchTouchEvent方法
  • View的dispatchTouchEvent方法


一、被分发的对象

被分发的对象是那些?被分发的对象是用户触摸屏幕而产生的点击事件,事件主要包括:按下、滑动、抬起与取消。这些事件被封装成MotionEvent对象。该对象中的主要事件如下表所示:

事件

触发场景

单次触发的次数

MotionEvent.ACTION_DOWN

在屏幕按下时

1次

MotionEvent.ACTION_MOVE

在屏幕上滑动时

0次或多次

MotionEvent.ACTION_UP

在屏幕抬起时

0次或1次

MotionEvent.ACTION_CANCLE

滑动超出控件边界时

0次或1次

按下、滑动、抬起、取消这几种事件组成了一个事件流。事件流以按下为开始,中间可能有多次滑动,以抬起或取消结束。

二、分发事件的组件

分发事件的组件:分发事件者,包括Activity、View和ViewGroup。它们三者的一般结构为:

Android事件分发郭 安卓的事件分发_事件分发

组件

特点

例子

Activity

视图类

如MainActivity

ViewGroup

View的容器,可以包含若干View

各种布局类

View

UI类组件的基类

如Button、textview

三、分发的核心方法

负责对事件进行分发的方法主要有三个
dispatchTouchEvent()
onTouchEvent()
onInterceptTouchEvent()
不是所有的组件都有这三个方法:

组件

dispatchTouchEvent

onTouchEvent

onInterceptTouchEvent

Activity

存在

存在

不存在

ViewGroup

存在

存在

存在

View

存在

存在

不存在

四、事件分发过程

Android事件分发郭 安卓的事件分发_事件点击原理_02


分发方法dispatchTouchEvent

Activity的dispatchTouchEvent方法

public boolean dispatchTouchEvent(MotionEvent ev) {
    if (child.dispatchTouchEvent(ev)) {
        return true;    //如果子View消费了该事件,则返回TRUE,让调用者知道该事件已被消费
    } else {
        return onTouchEvent(ev);    //如果子View没有消费该事件,则调用自身的onTouchEvent尝试处理。
    }
}

当事件传递给Activity后,它先将事件分发给子View处理。

  • 如果经过子View层层传递或处理后,该事件被消费了(即返回了true),则Activity的分发方法也返回true,同样也表示该事件已经被消费了。
  • 如果经过子View层层传递或处理后,该事件没有被消费(即返回了false),则Activity的分发方法就不会返回true了,而是调用onTouchEvent()去处理,看其实际的处理情况。
  • 如果onTouchEvent消费了事件,那依然能返回true(表示已消费事件),这个true作为dispatchTouchEvent的返回值,让调用它的对象知道该Activity已经消费了事件。
  • 如果onTouchEvent没有消费该事件,那就返回false(表示未消费事件),这个false作为dispatchTouchEvent的返回值,让调用它的对象知道该Activity没有消费事件,需要继续处理。

ViewGroup的dispatchTouchEvent方法

public boolean dispatchTouchEvent(MotionEvent ev) {
    if (!onInterceptTouchEvent(ev)) {
        return child.dispatchTouchEvent(ev);    //不拦截,则传给子View进行分发处理
    } else {
        return onTouchEvent(ev);    //拦截事件,交由自身对象的onTouchEvent方法处理
    }
}

ViewGroup的dispatchTouchEvent 多了一个onInterceptTouchEvent方法。当事件传入时,首先会调用onInterceptTouchEvent。

  • 如果该方法返回了false(表示不拦截),则交给子View去调用dispatchTouchEvent()方法
  • 如果该方法返回了true(表示拦截),则直接交给该ViewGroup对象的onTouchEvent(ev)方法处理,具体是否能处理以onTouchEvent()的实际情况为准。
  • 如果 ViewGroup 重写了 onInterceptTouchEvent或者onTouchEvent 并满足拦截条件就会返回true,常见的有自定义手势监听,滑动处理等

View的dispatchTouchEvent方法

public boolean dispatchTouchEvent(MotionEvent ev) {
    //如果该对象的监听成员变量不为空,则会调用其onTouch方法,
    if (mOnTouchListener != null && mOnTouchListener.onTouch(this, event)) {
        return true;    //若onTouch方法返回TRUE,则表示消费了该事件,则dispachtouTouchEvent返回TRUE,让其调用者知道该事件已被消费。
    }
    return onTouchEvent(ev);    //若监听成员为空或onTouch没有消费该事件,则调用对象自身的onTouchEvent方法处理。
}

方法调用后,会先对mOnTouchListener判空,如果之前Set了Listener,则会调用其onTouch方法。

  • 若onTouch方法返回TRUE,则dispatchTouchEvent也会返回TRUE,表示消费该事件。
  • 若onTouch方法返回FALSE,或者mOnTouchListener本来就是空,则调用自身的onTouchEvent()来处理,是否消费事件,可以由其返回值判断。