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>回味起来却有久久不会退去的余香。