认识一下Android 事件分发机制

1、引子

由于android是采用分层布局(可以想象成PS时的图层概念一样),这样才可以在有限大小的手机屏幕上完成一些复杂的操作。当手指点击屏幕开始,这些动作在各层之间如何传递?就引出了Android的事件分发机制。之所以称为事件,是由于在Android中将所有在屏幕的动作封装成3个事件

ACTION_DOWN:手指按下

ACTION_MOVE:手指在屏幕滑动

ACTION_UP:手指从屏幕抬起

每次都是从ACTION_DOWN开始,到ACTION_UP结束,中间伴随着ACTION_MOVE;有了事件就对应着事件处理3个重要的方法

【1】事件分发dispatchTouchEvent(MotionEvent ev)

【2】事件拦截 onInterceptTouchEvent(MotionEvent ev)

【3】事件响应 onTouchEvent(MotionEvent ev)

初始情况返回值都是False,表示自身未处理需要继续流程

其中ViewGroup以及继承ViewGroup的容器控件如布局文件RelativeLayout等,需回调这三个方法;通常View则只回调【1】【3】,对应一些显示控件如button等。

三者之间的关系如下(以ViewGroup为例):

这里一定要注意的是调用自身的dispatchTouchEvent后若继续让后面view处理,则再调用后面view的dispatchTouchEvent,直到哪个控件开始处理则会调用对应的onTouchEvent方法,这在源码中可以看出。

2、生活中的实例

先来感性认识一下:

Activity——部门boss

MyViewGroup(重写的RelativeLayout——ViewGroup容器控件)——项目组boss

MyButton(重写的Button控件——view控件)——屌丝程序员

正常情况下

事件传递的顺序:(Activity—Window(ViewGroup布局)——View)

Activity(部门boss)——>MyViewGroup(项目组boss)——>重写的MyButton(屌丝程序员)

事件处理的顺序:

重写的MyButton(屌丝程序员)——>MyViewGroup(项目组boss)——>Activity(部门boss)

事件传递的返回值布尔类型 True 表示拦截在拦截处消化无需上传(下发) False不拦截继续流程

事件处理的返回值布尔类型 True 已处理无需上级审核 False未处理需要上级审核

情形一:正常流程

因此对于上面的例子正常情况下层层处理流程如下

三大函数默认都是返回false,所以可以不拦截,直接分发上传,走完整个流程。可以形象解释为:部门boss把任务指派给项目组boss,项目组boss再指派给程序员,然后程序员搞定了汇报给他的上级项目组boss,然后由项目组汇报给部门boss

情形2:遇到好心项目组boss

要是某一步处理返回true表示本层已经处理完无需下发,比如MyViewGroup的 onInterceptTouchEvent 返回true,则流程如下

解释为:好比部门boss把任务下发给项目组boss,他觉得比较简单,就自己搞定了,然后告诉了部门boss

3、示例代码

重写其3个事件处理函数,函数方法内内打上LOG便于观察

关键代码如下,Mybutton重写【1】【3】同样是在函数内部打上Log

MyViewGroup继承RelativeLayout,(Mybutton继承Button控件)

<span style="font-size:18px;">/** * Created by ELVIS on 2015/10/18. * */public class MyViewGroup extends RelativeLayout{private final static String TAG = "MyViewGroup";public MyViewGroup(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:Log.i(TAG, "MyViewGroup dispatchTouchEvent–ACTION_DOWN");break;case MotionEvent.ACTION_MOVE:Log.i(TAG, "MyViewGroup dispatchTouchEvent–ACTION_MOVE");break;case MotionEvent.ACTION_UP:Log.i(TAG, "MyViewGroup dispatchTouchEvent–ACTION_UP");break;} //return super.dispatchTouchEvent(ev);return true;}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:Log.d(TAG, "MyViewGroup onInterceptTouchEvent–ACTION_DOWN");break;case MotionEvent.ACTION_MOVE:Log.d(TAG, "MyViewGroup onInterceptTouchEvent–ACTION_MOVE");break;case MotionEvent.ACTION_UP:Log.d(TAG, "MyViewGroup onInterceptTouchEvent–ACTION_UP");break;}return super.onInterceptTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent ev) {switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:Log.i(TAG, "MyViewGroup onTouchEvent–ACTION_DOWN");break;case MotionEvent.ACTION_MOVE:Log.i(TAG, "MyViewGroup onTouchEvent–ACTION_MOVE");break;case MotionEvent.ACTION_UP:Log.i(TAG, "MyViewGroup onTouchEvent–ACTION_UP");break;}return super.onTouchEvent(ev);}}</span>回味起来却有久久不会退去的余香。

认识一下Android 事件分发机制

相关文章:

你感兴趣的文章:

标签云: