Android事件分发机制是核心知识点,也是难点。
在了解事件分发之前,先进行一个感性的认知。
答:点击事件(Touch
事件)
当用户触摸屏幕时(View
或 ViewGroup
派生的控件),将产生点击事件(Touch
事件)。Touch
事件的相关细节(发生触摸的位置、时间等)被封装成MotionEvent
对象。
事件类型 | 具体动作 |
---|---|
MotionEvent.ACTION_DOWN | 按下View(所有事件的开始) |
MotionEvent.ACTION_UP | 抬起View(与DOWN对应) |
MotionEvent.ACTION_MOVE | 滑动View |
MotionEvent.ACTION_CANCEL | 结束事件(非人为原因) |
从手指接触屏幕 至 手指离开屏幕,这个过程产生的一系列事件:
所谓点击事件的事件分发,其实就是对MotionEvent
事件的分发过程,即当一个MotionEvent
产生了以后,系统需要把这个事件传递到一个具体的View
,而这个传递的过程就是分发过程。
Android的UI界面由Activity
、ViewGroup
、View
及其派生类组成。
是从上往下(Activity–>ViewGroup–>View) 传递的。
如果上一次拦截了,就不会继续往下传递;如果未拦截,就调用自己这一层的onTouchEvent()
方法。
核心方法有dispatchTouchEvent()
、onInterceptTouchEvent()
和onTouchEvent()
其中View
(不含ViewGroup
)没有onInterceptTouchEvent()
方法。
public boolean dispatchTouchEvent(MotionEvent event)
这个方法是最先调用的,是用来进行事件的分发。如果事件能够传递到当前View,那么此方法一定会被调用,返回结果受当前View
的onTouchEvent
和下级View
的dispatchTouchEvent
方法的影响,表示是否消耗当前事件。
public boolean onInterceptTouchEvent(MotionEvent event)
在上述方法内部调用,用来判断是否拦截某个事件。如果当前View
拦截了某个事件,那么在同一个事件序列当中,此方法不会被再次调用,返回结果表示是否拦截当前事件。
public boolean onTouchEvent(MotionEvent event)
在dispatchTouchEvent
方法中调用,用来处理点击事件,返回结果表示是否消费当前事件,如果不消费,则在同一个事件序列中,当前View
无法再次接受到事件。
在这个方法到底是什么关系了,下面一行伪代码可以表示:
public boolean dispatchTouchEvent(MotionEvent ev){
boolean consume=false;
if(onInterceptTouchEvent(ev)){
consume=onTouchEvent(ev);
}else{
consume=child.dispatchTouchEvent(ev);
}
return consume;
}
上述伪代码将三者的关系表现得淋漓尽致.通过上述的伪代码,我们也可以大致了解点击事件的传递规律:
对于一个根ViewGroup
来说,点击事件产生后,首先会传递给它,这时它的dispatchTouchEvent
就会被调用,如果这个ViewGroup
的onInterceptTouchEvent
方法返回true
,就表示它要拦截当前事件,接着事件就会交给这个ViewGroup
处理,即它的onTouchEvent
方法会被调用;如果这个ViewGroup
的onInterceptTouchEvent
方法返回false
,就表示它不拦截当前事件,这时当前事件就会继续传递给它的子元素,接着子元素的dispatchTouchEvent
会被调用,如此返回直到事件被最终处理。
上面是对Android事件分发的一个整体感性认知,至于具体的事件分发,请继续阅读:
Android事件分发机制完全解析(二) :View的事件分发机制
Android事件分发机制完全解析(三) :ViewGroup的事件分发机制
Android事件分发机制完全解析(四) :Activity的事件分发机制