1.前言
Android事件分发机制在Android开发者必须要了解的知识,并且是解决View的滑动冲突的基础。
2.事件分发的基础
要想了解事件分发的机制,我们必须要知道事件分发的基础,即,事件分发的对象和流程。
2.1 事件分发的定义
将点击事件(MotionEvent)向某个View进行传递并最终得到处理。
2.2 事件分发的对象
当用户触摸屏幕时(View或ViewGroup派生的控件),将产生点击事件(Touch事件)。这个事件就是分发的对象。
主要发生的Touch事件有如下四种:
MotionEvent.ACTION_DOWN:按下View(所有事件的开始)
MotionEvent.ACTION_MOVE:滑动View
MotionEvent.ACTION_CANCEL:非人为原因结束本次事件
MotionEvent.ACTION_UP:抬起View(与DOWN对应)
2.3 事件的传递流程
一个点击事件产生后,传递顺序是:Activity(Window) -> ViewGroup -> View
1.View是所有UI组件的基类
一般Button、ImageView、TextView等控件都是继承父类View
2.ViewGroup是容纳UI组件的容器,即一组View的集合(包含很多子View和子VewGroup)
- 其本身也是从View派生的,即ViewGroup是View的子类
- 是Android所有布局的父类或间接父类:项目用到的布局(LinearLayout、RelativeLayout等),都继承自ViewGroup,即属于ViewGroup子类。
- 与普通View的区别:ViewGroup实际上也是一个View,只不过比起View,它多了可以包含子View和定义布局参数的功能。
3. 事件分发的主要方法介绍
事件分发主要涉及到三个主要方法:dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()。
下面用张图来说明这三个方法的含义及作用。
这三个方法的联系可以用下面的伪代码来表示:
// 点击事件产生后,会直接调用dispatchTouchEvent()方法
public boolean dispatchTouchEvent(MotionEvent ev) {
//代表是否消耗事件
boolean consume = false;
if (onInterceptTouchEvent(ev)) {
//如果onInterceptTouchEvent()返回true则代表当前View拦截了点击事件
//则该点击事件则会交给当前View进行处理
//即调用onTouchEvent ()方法去处理点击事件
consume = onTouchEvent (ev) ;
} else {
//如果onInterceptTouchEvent()返回false则代表当前View不拦截点击事件
//则该点击事件则会继续传递给它的子元素
//子元素的dispatchTouchEvent()就会被调用,重复上述过程
//直到点击事件被最终处理为止
consume = child.dispatchTouchEvent (ev) ;
}
return consume;
}
上面的伪代码很好的总结了一个事件的分发机制。
这里总结如下:
点击事件产生后,首先传到的是ViewGroup,然后ViewGroup的dispatchTouchEvent()方法被调用。
如果onInterceptTouchEvent()返回true则代表当前View拦截了点击事件,时候调用ViewGroup的onTouchEvent()方法进行自我消耗,不往子View进行传递,如果onInterceptTouchEvent()返回false则往子View进行传递。
- 第二点onInterceptTouchEvent()返回false,事件往子View传递,这个时候子View的dispatchTouchEvent()方法被调用。如果子View是一个ViewGroup,重复上面的步骤。直到事件被最终处理。
4.从源码分析Android事件优先级
View的点击事件不但和ViewGroup的onInterceptTouchEvent()的返回值有关,还和事件的优先级有关,优先级高的事件能够屏蔽优先级低的事件,让优先级低的事件无法接收事件。
4.1 demo引入
下面我们以一个demo来引入事件优先级: