实践是检验真理的唯一标准!
重写事件分发机制,布局如下:
布局代码如下:
<com.example.mayn.mytesteventdispatchpro.MyOuterViewGroup
android:id="@+id/outer"
android:background="#ff0000"
android:layout_width="350dp"
android:layout_height="250dp">
<com.example.mayn.mytesteventdispatchpro.MyInnerViewGroup
android:id="@+id/inner"
android:background="#ffff00"
android:layout_width="250dp"
android:layout_gravity="center|center_horizontal"
android:layout_height="150dp">
<com.example.mayn.mytesteventdispatchpro.MyView
android:layout_width="150dp"
android:layout_height="75dp"
android:background="#0000ff"
android:layout_gravity="center"
android:id="@+id/view"
/>
</com.example.mayn.mytesteventdispatchpro.MyInnerViewGroup>
</com.example.mayn.mytesteventdispatchpro.MyOuterViewGroup>
每一个自定义view都重写了dispatchTouchEvent和onTouchEvent方法,viewGroup还重写了onInterceptTouchEvent方法。具体如下:
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.e("TEST","MyOuterViewGroup dispatchTouchEvent");
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
Log.e("TEST","MyOuterViewGroup dispatchTouchEvent ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e("TEST","MyOuterViewGroup dispatchTouchEvent ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e("TEST","MyOuterViewGroup dispatchTouchEvent ACTION_UP");
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.e("TEST","MyOuterViewGroup onInterceptTouchEvent");
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
Log.e("TEST","MyOuterViewGroup onInterceptTouchEvent ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e("TEST","MyOuterViewGroup onInterceptTouchEvent ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e("TEST","MyOuterViewGroup onInterceptTouchEvent ACTION_UP");
break;
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
Log.e("TEST","MyOuterViewGroup onTouchEvent");
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
Log.e("TEST","MyOuterViewGroup onTouchEvent ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e("TEST","MyOuterViewGroup onTouchEvent ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e("TEST","MyOuterViewGroup onTouchEvent ACTION_UP");
break;
}
return super.onTouchEvent(ev);
}
以下是举例各种点击情况下的事件分发:
一、点击外部viewgroup:
E/TEST: MyOuterViewGroup dispatchTouchEvent
E/TEST: MyOuterViewGroup dispatchTouchEvent ACTION_DOWN
E/TEST: MyOuterViewGroup onInterceptTouchEvent
E/TEST: MyOuterViewGroup onInterceptTouchEvent ACTION_DOWN
E/TEST: MyOuterViewGroup onTouchEvent
E/TEST: MyOuterViewGroup onTouchEvent ACTION_DOWN
E/TEST: MyOuterViewGroup dispatchTouchEvent
E/TEST: MyOuterViewGroup dispatchTouchEvent ACTION_MOVE
E/TEST: MyOuterViewGroup onTouchEvent
E/TEST: MyOuterViewGroup onTouchEvent ACTION_MOVE
E/TEST: MyOuterViewGroup dispatchTouchEvent
E/TEST: MyOuterViewGroup dispatchTouchEvent ACTION_UP
E/TEST: MyOuterViewGroup onTouchEvent
E/TEST: MyOuterViewGroup onTouchEvent ACTION_UP
E/TEST: Outer ViewGroup onClick
1)从上面可以看出,当点击外部viewGroup的时候,只有MyOuterViewGroup的事件分发方法有响应,分别调用dispatchTouchEvent和onTouchEvent方法,不论onInterceptTouchEvent方法返回默认还是true/false,在ACTION_MOVE和ACTION_UP时都不会去调用该方法了。
2)当dispatchTouchEvent返回false的时候,只会调用该方法的ACTION_DOWN,其余方法全部无响应,拦截。
3)当dispatchTouchEvent返回true的时候,
E/TEST: MyOuterViewGroup dispatchTouchEvent
E/TEST: MyOuterViewGroup dispatchTouchEvent ACTION_DOWN
E/TEST: MyOuterViewGroup dispatchTouchEvent
E/TEST: MyOuterViewGroup dispatchTouchEvent ACTION_MOVE
E/TEST: MyOuterViewGroup dispatchTouchEvent
E/TEST: MyOuterViewGroup dispatchTouchEvent ACTION_UP
该方法的所有ACTION都有响应。但是onTouchEvent方法无响应,拦截。
4)当dispatchTouchEvent返回为默认,不论onInterceptTouchEvent方法返回默认还是true/false,都会分发到onTouchEvent方法去。不拦截
5)当onTouchEvent返回为true时,
MyOuterViewGroup dispatchTouchEvent ACTION_DOWN
MyOuterViewGroup onInterceptTouchEvent ACTION_DOWN
MyView dispatchTouchEvent ACTION_DOWN
MyOuterViewGroup dispatchTouchEvent ACTION_MOVE
MyOuterViewGroup onInterceptTouchEvent ACTION_MOVE
MyOuterViewGroup dispatchTouchEvent ACTION_UP
MyOuterViewGroup onInterceptTouchEvent ACTION_UP
Inner ViewGroup onClick
所有ACTION都有响应,但是onClick事件无响应,拦截。但是内部的ViewGroup有onClick响应
6)当onTouchEvent返回为false时,
E/TEST: MyOuterViewGroup dispatchTouchEvent
E/TEST: MyOuterViewGroup dispatchTouchEvent ACTION_DOWN
E/TEST: MyOuterViewGroup onInterceptTouchEvent
E/TEST: MyOuterViewGroup onInterceptTouchEvent ACTION_DOWN
E/TEST: MyOuterViewGroup onTouchEvent
E/TEST: MyOuterViewGroup onTouchEvent ACTION_DOWN
同上面第2)条,只会调用ACTION_DOWN方法,其余全无响应。拦截
二、点击内部View
1)全部返回为默认情况下:
MyOuterViewGroup dispatchTouchEvent ACTION_DOWN
MyOuterViewGroup onInterceptTouchEvent ACTION_DOWN
MyView dispatchTouchEvent ACTION_DOWN
MyView onTouchEvent ACTION_DOWN
MyOuterViewGroup dispatchTouchEvent ACTION_MOVE
MyOuterViewGroup onInterceptTouchEvent ACTION_MOVE
MyView dispatchTouchEvent ACTION_MOVE
MyView onTouchEvent ACTION_MOVE
MyOuterViewGroup dispatchTouchEvent ACTION_UP
MyOuterViewGroup onInterceptTouchEvent ACTION_UP
MyView dispatchTouchEvent ACTION_UP
MyView onTouchEvent ACTION_UP
View onClick
从上面可以看出,全部返回默认的时候,先调用外部的viewgroup,然后调用内部的view。1.1)当外部viewgroup的dispatchTouchEvent返回false/true的时候,直接拦截;1.2)当外部viewgroup的onInterceptTouchEvent 返回false和true的时候,拦截,只有外部viewgroup有响应,外部viewgroup可以响应点击事件。
2)内部view的dispatchTouchEvent返回true时,该方法的所有ACTION都有响应。但是onTouchEvent方法无响应,拦截。
3)内部view的dispatchTouchEvent返回false时,只会调用该方法的ACTION_DOWN,外部InnerViewGroup的onClick响应。
三、结论如下:
1、对于dispatchTouchEvent方法,
1.1如果是viewgroup,1)返回为true则拦截,2)如果返回为false,则a)当前VG是最外层,则拦截,b)当前VG不是最外层,不论点击当前VG还是内部view,都是外层VG的onClick响应
1.2如果是view,1)返回true则拦截,2)返回false,上一层的VG的onClick响应
2、对于onInterceptTouchEvent方法,只有ViewGroup有,1)返回为true,则拦截,自己的onClick响应,2)返回为false,不拦截,点自己,自己的onClick响应,点内V,内V的onClick响应
3、对于onTouchEvent方法,
1.1如果是viewgroup,1)返回为true,则a)点自己,拦截,b)点内部view,不拦截,内部view的onClick响应。2)返回为false,则a)点自己,拦截,外部的VG的onClick响应,b)点内view,不拦截,内view的onClick响应
1.2如果是view,1)返回true则拦截,2)返回false,则上一层的onClick响应