在学习自定义控件时,发现SDK中对touch event的描述比较模糊,因此本身写了个demo并结合源代码测试了一下java
在View类中,处理TouchEvent的方法有:dispatchTouchEvent和onTouchEvent函数
在ViewGroup类中处理TouchEvent的方法有:ViewGroup、onInterceptTouchEvent和onTouchEvent布局
测试布局模型是:学习
<MyViewGroup> <MyView /> </MyViewGroup>
当点击View的时候测试
状况一:若是全部的处理函数都返回false,TouchEvent的传递路径是:spa
1) ViewGroup.dispatchTouchEvent-----------------ACTION_DOWN 2) ViewGroup.onInterceptTouchEvent--------------ACTION_DOWN 3) View.dispatchTouchEvent----------------------ACTION_DOWN 4) View.onTouchEvent----------------------------ACTION_DOWN 5) ViewGroup.onTouchEvent-----------------------ACTION_DOWN
并且只会受到ACTION_DOWN事件,不会收到ACTION_UP事件或者其它后续事件code
状况二:MyView的onTouchEvent返回true,其它都返回false时,结果跟状况一同样xml
1) ViewGroup.dispatchTouchEvent-----------------ACTION_DOWN 2) ViewGroup.onInterceptTouchEvent--------------ACTION_DOWN 3) View.dispatchTouchEvent----------------------ACTION_DOWN 4) View.onTouchEvent----------------------------ACTION_DOWN 5) ViewGroup.onTouchEvent-----------------------ACTION_DOWN
状况三:MyView的onTouchEvent和dispatchTouchEvent都返回true,其它返回false事件
1) ViewGroup.dispatchTouchEvent-----------------ACTION_DOWN 2) ViewGroup.onInterceptTouchEvent--------------ACTION_DOWN 3) View.dispatchTouchEvent----------------------ACTION_DOWN 4) View.onTouchEvent----------------------------ACTION_DOWN
你会发现ViewGroup的onTouchEvent不会收到消息,可是仍是收不到ACTION_UP事件get
状况四:MyView的onTouchEvent和dispatchTouchEvent都返回true,MyViewGroup的dispatchTouchEvent也返回true的时候:
1) ViewGroup.dispatchTouchEvent-----------------ACTION_DOWN 2) ViewGroup.onInterceptTouchEvent--------------ACTION_DOWN 3) View.dispatchTouchEvent----------------------ACTION_DOWN 4) View.onTouchEvent----------------------------ACTION_DOWN 1) ViewGroup.dispatchTouchEvent-----------------ACTION_UP 2) ViewGroup.onInterceptTouchEvent--------------ACTION_UP 3) View.dispatchTouchEvent----------------------ACTION_UP 4) View.onTouchEvent----------------------------ACTION_UP
这时候就能收到ACTION_UP事件
ViewGroup dispatchTouchEvent(event)传递的主要逻辑的伪码:
private View mMotionTarget;//保存真正处理响应的View if (action == MotionEvent.ACTION_DOWN) //ACTION_DOWN事件 { if (mMotionTarget != null) { mMotionTarget = null; } if (!onInterceptTouchEvent()){ //若是拦截方法返回false,即不拦截 for (allChild){ //循环全部子View或者ViewGroup if (child.dispatchTouchEvent()){ //若是child的dispatchTouchEvent返回true,即处理了事件 mMotionTarget = child; return true; //若是child处理的消息,则直接返回true } } } else { //若是拦截方法返回true,即拦截此事件 不把此事件传递给child,即child将不会收到此事件 } } if (mMotionTarget == null){ //调用本身的onTouchEvent方法 //两种状况会走这个分支:1)ACTION_DOWN事件,child都返回false //2)后续事件,而且以前的ACTION_DOWN事件,child都返回false return onTouchEvent(); } //如下是后续事件的处理过程 if (onInterceptTouchEvent()){ //若是事件被拦截 mMotionTarget.dispatchTouchEvent(ACTION_CANCEL);//给目标child发送cancel事件 return true;//直接返回 } else {//事件没有被拦截 return mMotionTarget.dispatchTouchEvent();//把事件交给child处理 }
View的dispatchTouchEvent(event)伪码很简单:
return onTouchEvent();
由此能够看出,要想收到ACTION_DOWN的后续事件的条件是路径上的全部dispatchTouchEvent都得返回true
而且本身的onTouchEvent得返回true,并且路径上没有拦截器拦截事件