Android事件分发机制
Android事件分发机制算是Android高级篇的基础了,程序猿一定要对其有所了解。
(1)确定事件分发的对象
当用户点击View或ViewGroup时就产生了触摸(Touch)事件,Touch相关的细节被封装成了MotionEvent
对象。当我们自定义View时经常重写onTouchEvent
方法,比如:
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_CANCEL:
break;
case MotionEvent.ACTION_UP:
break;
}
return super.onTouchEvent(event);
}
onTouchEvent
可以监听到触摸(Touch)事件。
常用的Touch事件有四种:
- MotionEvent.ACTION_DOWN:按下View
- MotionEvent.ACTION_MOVE:滑动View
- MotionEvent.ACTION_CANCEL:非人为原因取消事件
- MotionEvent.ACTION_UP:抬起View
View事件的基本流程是:
用户按下View,触发ACTION_DOWN
事件-->用户拖动或滚动View,触发ACTION_MOVE
事件-->用户抬起,放开View,触发ACTION_UP
事件。
ACTION_CANCEL
事件的触发非人为触发,也许是程序猿代码中主动取消,也许是发生了异常导致取消。
(2)事件分发的本质
本质上是将点击时间的出来传递到View本身去处理,这个过程叫做分发过程。
(3)事件传递的载体
事件传递的载体是:Activity(Window)、ViewGroup、View。
假设点击一个按钮,事件的传递顺序是:Activity(Window)-->ViewGroup-->View
下图是Activity、ViewGroup、View的层级图,其实Activity上面还有一层叫PhoneWindow
,但不是本章重点。
请先记住触摸事件的传递顺序:Activity(Window)-->ViewGroup-->View
- Activity:它是Android界面的基本
- ViewGroup:有线性布局、相对布局、约束布局、帧布局、表格布局、RecyclerView、其它自定义ViewGroup
- View:比如,TextView、ImageView或者其它自定义View
(4)事件的分发由哪些方法协调?
事件的分发由dispatchTouchEvent()
、onInterceptTouchEvent()
、onTouchEvent()
相互协调的。
-
onTouchEvent()
:负责处理触摸事件
事件分发到最后,总是由 onTouchEvent()
来处理触摸事件。
它的返回值代表的意义:
[true]
:直接结束
[super或false]
:执行上级的onTouchEvent()
方法
-
dispatchTouchEvent()
:负责分发触摸事件
事件的分发总是由这个方法开始,根据不同的返回值做出相应的处理:
[true]
:直接结束事件的分发
[false]
:执行上级的onTouchEvent()
方法去处理触摸事件,最后结束事件的分发
[super]
:继续分发事件
-
onInterceptTouchEvent()
:负责拦截触摸事件
只有在ViewGroup中才有这个方法,这个方法专门负责事件的拦截工作,根据返回值处理不同的结果:
[true]
:执行ViewGroup的onTouchEvent()
事件;
[super或false]
:执行View的dispatchTouchEvent()
方法
(5)事件在Activity中是如何处理的?
前提条件:Activity中有一个按钮(View),按钮在一个布局(ViewGroup)中。
我们都知道触摸事件的传递顺序:Activity(Window)-->ViewGroup-->View
,那么在Activity中事件是如何处理的呢?
Activity中有一个dispatchTouchEvent
方法,当有触摸事件时,最先执行的方法就是dispatchTouchEvent
,它的返回类型是一个boolean类型,默认情况下返回super.dispatchTouchEvent(ev)
,当返回super.dispatchTouchEvent(ev)
时,事件将传递给ViewGroup,但是如果返回true或者false时,事件就会直接结束,不会传递给ViewGrou,更不会传递给View。
比如,在Activity中重写dispatchTouchEvent
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return true;
}
或
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return false;
}
这种情况下,按钮是不可能监听到点击事件的,一般我们不会在Activity中重写dispatchTouchEvent
方法,就默认返回super.dispatchTouchEvent(ev)
,让它把事件传递到ViewGroup即可。
(6)事件在ViewGroup中是如何处理的?
当事件从Activity传递到ViewGroup之后,ViewGroup是如何处理这个事件的呢?
在ViewGroup中,事件首先被分发到ViewGroup的dispatchTouchEvent
方法:
- 如果返回true则直接结束分发;
- 如果返回false,则执行Activity的
onTouchEvent
方法,Activity的onTouchEvent
方法不管返回什么都直接结束分发; - 如果返回
super.dispatchTouchEvent(ev)
,则执行onInterceptTouchEvent
方法;
onInterceptTouchEvent
的返回值解析如下:
- 如果返回true,则执行ViewGroup的
onTouchEvent
方法; - 如果返回super或者false,则执行View的
dispatchTouchEvent
方法;
onTouchEvent
的返回值解析如下:
- 返回true,直接结束事件
- 否则,执行Activity的
onTouchEvent
方法
(7)事件在View中是如何处理的?
在View中,事件首先被分发到View的dispatchTouchEvent
方法:
- 返回true,结束事件
- 返回false,执行ViewGroup的
onTouchEvent
方法 - 返回super,则直接执行View的
onTouchEvent
方法
(8)事件分发流程图(是重点,要记住)
以上这张图要记住,上面说了那么多废话,记不住不要紧,只要将这张图记住就可以了。
事件分发流程图.png(9)总结
- 请记住以上的一张图,因为这张图才是世间分发机制的精髓所在,其实这张图就是事件分发机制的全部了;
- 事件分发机制是实现自定义View的基础,所以一定要了解;
- 现在很多嵌套View都存在触摸事件冲突问题,这时就需要事件分发机制的知识来解决这个问题了。
[本章完...]