1 前言
最近在找工作,面试官经常会问有没有做个自定义view,接下来的话一般都会问Android事件分发机制。看过很多次,但是每隔一段时间又忘记了,或者面试时说的也很乱。我想了下,用讲故事的方式来说这个感觉不错,小白都能看懂。
2 事件分发机制分类
- 事件的分发
public boolean dispatchTouchEvent(MotionEvent ev)
此方法虽然是事件分发的第一步,但一般情况下,我们不太会去改写这个方法,所以暂时不管这个方法。
- 事件的拦截(View中没有该方法)
public boolean onInterceptTouchEvent(MotionEvent event)
返回值理解:true,拦截,不继续;false,不拦截,继续流程。
默认值是false。
- 事件的处理
public boolean onTouchEvent(MotionEvent event)
返回值理解:true,处理了,不用审核了;false,给上级处理。
默认值是false。
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
3 开始讲故事
假如你是一家小公司的程序猿,你们公司是给第三方客户做App的,其实就是一家外包公司。
公司主要有三个角色:身为程序猿的你,你的经理,公司的老板。
分别取名为: MyView、MyManagerViewGroup、MyBossViewGroup
对应如下图:

3.1 事件的拦截
与事件拦截机制有关的方法是:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev);
}
3.1.1 全部未拦截
有一天,客户下了个订单,订单提交给boss。boss说可以做(返回false,不拦截),然后下发给经理,经理也说可以做(返回false,不拦截),经理再下发给你,因为你是程序猿没人权,不能做也得做,所以没有拦截判断。
这也是未重写任何方法,未修改任何代码的情况下,默认返回是false。
此时顺序是:
老板-->经理-->你
类似于当你点击蓝色的view颜色块时,事件的传递顺序是:
红-->绿-->蓝
MyBossViewGroup-->MyManagerViewGroup-->MyView
logcat打印如下:

借用Android群英传图:

3.1.2 在中间拦截
客户下的订单在boss那里通过了(返回false,不拦截)。但是到了经理那里,经理觉得这App太难做了,公司实力不够做不了(返回true,拦截,不继续)。
事件在经理处就消费掉了,你挺开心的,因为跟你没什么关系,可以不要加班了。
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.d(TAG, "MyManagerViewGroup onInterceptTouchEvent--> " + ev.getAction());
// return super.onInterceptTouchEvent(ev);
return true;
}
此时顺序是:
老板-->经理
事件的传递顺序是:
红-->绿
MyBossViewGroup-->MyManagerViewGroup

借用Android群英传图:

3.1.3 在最上层拦截
客户下了个小单后,boss觉得利润太低了,不是很想做(返回true,拦截,不继续),显然没你跟经理什么事。
事件在boss处就消费掉了,你和经理都挺开心的,因为跟你们没什么关系,可以开开心心回家了。
此时顺序是:
老板
事件的传递顺序是:
红
MyBossViewGroup

借用Android群英传图:

3.2 事件的处理
与事件处理机制有关的方法是
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
3.2.1 正常处理
任务下发后,你发现客户的App挺容易做的,于是你很快就做完了。做完后交给经理看,经理看完感觉还不错,再交给boss审核。
这也是未重写任何方法,未修改任何代码的情况下。
此时顺序是:
你做完任务-->经理审核-->boss审核
事件的传递顺序是:
蓝-->绿-->红
View onTouchEvent-->MyManagerViewGroup onTouchEvent-->MyBossViewGroup onTouchEvent

3.2.2 在View处理
任务下发后,你发现客户的App太难做了,估计要疯狂加班很长时间,想到很久每周末,你的小宇宙爆发了,老子不干了!(返回true,处理了)
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.v(TAG, "View onTouchEvent " + event.getAction());
// return super.onTouchEvent(event);
return true;
}
此时顺序是:
你辞职不管
事件的传递顺序是:
蓝
View onTouchEvent

这里的log打印长了很多,还有0和1两种情况。
当点击屏幕通常会产生两或三个事件——按下(MotionEvent.ACTION_DOWN),滑动(MotionEvent.ACTION_MOVE),抬起手(MotionEvent.ACTION_UP)。
0表示ACTION_DOWN事件
1表示ACTION_UP事件
2表示ACTION_MOVE事件
在看面的Log日志,发现在执行ACTION_DOWN事件时,MyView的onTouchEvent方法返回true后,两个ViewGroup都不执行onTouchEvent方法,这也就是说MyView直接结束了这次事件,不再传回两个ViewGroup。但是,在结束了ACTION_DOWN事件后,紧接着开始执行了ACTION_UP事件,说明只有当MyView的onTouchEvent返回true才会执行下面的事件。
3.2.3 在中间处理
boss布置完任务后发现太忙了,对经理说:这个App的效果交给你来全权处理,不要向我汇报了。
此时顺序是:
你做完任务-->经理审核
事件的传递顺序是:
蓝-->绿
View onTouchEvent-->MyManagerViewGroup onTouchEvent

返回true后直接结束事件,但是在第二次处理事件的时候,MyView就没再参与事件的处理,也就是说一旦onTouchEvent返回值为true就会导致在本次处理过程中后面的事件将不再分发给该View。
网友评论