Android View事件分发机制 小记
Android事件分发机制,一直以来只知道onInterceptTouchEvent返回true的时候,表示进行拦截,交给本身View的onTouchEvent处理;如果返回false,表示不进行拦截,交给子View处理。现在花一点事件对事件处理做一些总结。
第一.研究对象。
需要研究的对象,我将它分为两类,第一类:ViewGroup,也就是可以包含其他View或者ViewGroup;第二类,View,不能包含其他View。这两类的差别在于ViewGroup,包含dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent方法。而View只包含onTouchEvent方法。(注意我这里说的View和android上定义的View有差别,androi上ViewGroup是继承View的)。
第二.研究的主要函数。
研究的函数包括三个:dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent。它们之间的关系可以用伪代码表示:
public boolean dispatchTouchEvent(Motiontion ev){ boolean consume=false; if(onInterceptTouchEvent(ev)){ consume=onTouchEvent(ev); } else{ consume=child.dispatchTouchEvent(ev); } return consume; }
我的理解:若onInterceptTouchEvent进行拦截了,则返回onTouchEvent(ev)的值;否则交给子View去处理。
第三。几种情况分析。
接下去,我写了1个Demo进行测试,布局比较简单,父View里头套了一个子View。
1.若父View的onInterceptTouchEvent中的Down返回true,则子View不会接收到touch事件。
父View的代码:
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { int action = ev.getActionMasked(); switch (action) { case MotionEvent.ACTION_DOWN: flag = true; Log.e("error", "father_inter_action_down="+flag); break; case MotionEvent.ACTION_MOVE: Log.e("error", "father_inter_action_move"); break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: Log.e("error", "father_inter_action_cancel"); break; default: break; } return flag; } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getActionMasked(); switch (action) { case MotionEvent.ACTION_DOWN: touchFlag = true; Log.e("error", "father_touch_action_down"); break; case MotionEvent.ACTION_MOVE: Log.e("error", "father_touch_action_move"); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: Log.e("error", "father_touch_action_cancel"); break; default: break; } return touchFlag; } }
子View的代码:
public boolean onTouchEvent(MotionEvent event) { int action = event.getActionMasked(); switch (action) { case MotionEvent.ACTION_DOWN: touchFlag = true; Log.e("error", "child_touch_action_down"); break; case MotionEvent.ACTION_MOVE: Log.e("error", "child_touch_action_move"); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: Log.e("error", "child_touch_action_cancel"); break; default: break; } return touchFlag; }
LOG日志为:
01-04 21:46:36.724: E/error(12032): father_inter_action_down=true
01-04 21:46:36.726: E/error(12032): father_touch_action_down
01-04 21:46:36.759: E/error(12032): father_touch_action_move
……
01-04 21:46:36.776: E/error(12032): father_touch_action_move
01-04 21:46:37.178: E/error(12032): father_touch_action_cancel
结论:从log中可以看到 子View 没有获得touch事件。
2.若父View的onInterceptTouchEvent中的Down返回false,并且子View中Touch事件返回True。
代码部分:
父View中的onInterceptTouchEvent:
case MotionEvent.ACTION_DOWN: flag = false; Log.e("error", "father_inter_action_down="+flag); break;
子View中的TouchEvent返回true。
LOG日志为:
01-04 21:17:08.974: E/error(30622): father_inter_action_down=false
01-04 21:17:08.975: E/error(30622): child_touch_action_down
01-04 21:17:09.004: E/error(30622): father_inter_action_move
……
01-04 21:17:09.336: E/error(30622): father_inter_action_move
01-04 21:17:09.337: E/error(30622): child_touch_action_move
01-04 21:17:09.350: E/error(30622): father_inter_action_cancel
01-04 21:17:09.351: E/error(30622): child_touch_action_cancel
结论:从上诉可以看出,父View并不会再调用自己的onTouch方法,但是之后的事件:ACTION_MOVE和ACTION_DOWN都会经过父View的onInterceptTouchEvent方法,由于均未进行拦截。所以这些后续事件都传到了子View中。
3.若父View的onInterceptTouchEvent中的Down返回false,并且子View中Touch事件返回false。
Log日志为:
01-04 21:18:21.334: E/error(851): father_inter_action_down=false
01-04 21:18:21.335: E/error(851): child_touch_action_down
01-04 21:18:21.335: E/error(851): father_touch_action_down
01-04 21:18:21.368: E/error(851): father_touch_action_move
01-04 21:18:21.384: E/error(851): father_touch_action_move
01-04 21:18:21.401: E/error(851): father_touch_action_move
……
01-04 21:18:21.783: E/error(851): father_touch_action_move
01-04 21:18:21.800: E/error(851): father_touch_action_move
01-04 21:18:21.801: E/error(851): father_touch_action_cancel
结论:从上诉可以看出,子View未消耗该touch事件,则该事件向上进行传递,调用父View的onTouch方法(不调用onInterceptTouchEvent方法),由于父View中的onTouch方法对所有事件都返回了True,表示对所有事件进行消耗。