百度”android事件分发”一堆文章,都是围绕dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent三个方法开始讨论源码的,看书也很难理解,而且容易忘记,尤其一些理论的,所以今天我们不分析源码,简单粗暴的动手实践去探索下它.
首先我们需要准备一些东西:
- 3个自定义ViewGroup(ViewGroup1,ViewGroup2,ViewGroup3),看到自定义别慌,就是继承下ViewGroup,就这么粗暴.
- 1个自定义View,和上面一样粗暴.
- 1个Activity,自动生成就行,只需要改下xml布局.
ps:这里我多说一句,这里用RelativeLayout,LinearLayout什么的都是可以的,反正它们的爸爸都是ViewGroup,ViewGroup的爸爸是View,自定义是为了重写dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent从而打印日志,方便我们观察,不过自定义View没有onInterceptTouchEvent方法.
下面来布局我们的xml布局,就是叠罗汉式的,从下到上依次是ViewGroup1,ViewGroup2,ViewGroup3,View.
代码(这里是ViewGroup1的代码,其他的改改日志就好):
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.e("Debug", "MyViewGroup1:dispatchTouchEvent ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e("Debug", "MyViewGroup1:dispatchTouchEvent ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e("Debug", "MyViewGroup1:dispatchTouchEvent ACTION_UP");
break;
default:
break;
}
boolean dispatchTouchEvent = super.dispatchTouchEvent(ev);
Log.e("Debug", "MyViewGroup1:super.dispatchTouchEvent(ev)" + dispatchTouchEvent);
return dispatchTouchEvent;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.e("Debug", "MyViewGroup1:onInterceptTouchEvent ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e("Debug", "MyViewGroup1:onInterceptTouchEvent ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e("Debug", "MyViewGroup1:onInterceptTouchEvent ACTION_UP");
break;
default:
break;
}
boolean onInterceptTouchEvent = super.onInterceptTouchEvent(event);
Log.e("Debug", "MyViewGroup1:super.onInterceptTouchEvent(event)" + onInterceptTouchEvent);
return onInterceptTouchEvent;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.e("Debug", "MyViewGroup1:onTouchEvent ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e("Debug", "MyViewGroup1:onTouchEvent ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e("Debug", "MyViewGroup1:onTouchEvent ACTION_UP");
break;
default:
break;
}
boolean onTouchEvent = super.onTouchEvent(event);
Log.e("Debug", "MyViewGroup1:super.onTouchEvent(event)" + onTouchEvent);
return onTouchEvent;
}
布局文件(这里注意下,MyView里需要添加android:clickable=”true”,自定义view默认是不可点击的,button这类的默认是可以点击的)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.wjy.app.test.MyViewGroup1
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.wjy.app.test.MyViewGroup2
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.wjy.app.test.MyViewGroup3
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.wjy.app.test.MyView
android:id="@+id/my_view"
android:layout_width="300dp"
android:layout_height="300dp"
android:background="@android:color/holo_blue_bright"
android:clickable="true" />
</com.wjy.app.test.MyViewGroup3>
</com.wjy.app.test.MyViewGroup2>
</com.wjy.app.test.MyViewGroup1>
</RelativeLayout>
测试还有三十秒到达战场,碾碎它们.一顿控制变量法操作,操作的就是三个方法的boolean返回值,然后我们轻轻的点击MyView.
dispatchTouchEvent方法
E/Debug: MyViewGroup1:dispatchTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup2:dispatchTouchEvent ACTION_DOWN
E/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_DOWN
E/Debug: MyViewGroup2:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup3:dispatchTouchEvent ACTION_DOWN
E/Debug: MyViewGroup3:onInterceptTouchEvent ACTION_DOWN
E/Debug: MyViewGroup3:super.onInterceptTouchEvent(event)false
E/Debug: MyView:dispatchTouchEvent ACTION_DOWN
E/Debug: MyView:onTouchEvent ACTION_DOWN
E/Debug: MyView:super.onTouchEvent(event)true
E/Debug: MyView:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup3:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup1:dispatchTouchEvent ACTION_MOVE
E/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_MOVE
E/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup2:dispatchTouchEvent ACTION_MOVE
E/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_MOVE
E/Debug: MyViewGroup2:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup3:dispatchTouchEvent ACTION_MOVE
E/Debug: MyViewGroup3:onInterceptTouchEvent ACTION_MOVE
E/Debug: MyViewGroup3:super.onInterceptTouchEvent(event)false
E/Debug: MyView:dispatchTouchEvent ACTION_MOVE
E/Debug: MyView:onTouchEvent ACTION_MOVE
E/Debug: MyView:super.onTouchEvent(event)true
E/Debug: MyView:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup3:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup1:dispatchTouchEvent ACTION_UP
E/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_UP
E/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup2:dispatchTouchEvent ACTION_UP
E/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_UP
E/Debug: MyViewGroup2:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup3:dispatchTouchEvent ACTION_UP
E/Debug: MyViewGroup3:onInterceptTouchEvent ACTION_UP
E/Debug: MyViewGroup3:super.onInterceptTouchEvent(event)false
E/Debug: MyView:dispatchTouchEvent ACTION_UP
E/Debug: MyView:onTouchEvent ACTION_UP
E/Debug: MyView:super.onTouchEvent(event)true
E/Debug: MyView:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup3:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)true
结论: Android事件分发顺序是先到ViewGroup层,在传递到View层(如上图从最底层开始传递)。
onInterceptTouchEvent方法
//ViewGroup1 中 onInterceptTouchEvent返回true
E/Debug: MyViewGroup1:dispatchTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:onTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:super.onTouchEvent(event)false
E/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)false
//ViewGroup2 中 onInterceptTouchEvent返回true
E/Debug: MyViewGroup1:dispatchTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup2:dispatchTouchEvent ACTION_DOWN
E/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_DOWN
E/Debug: MyViewGroup2:onTouchEvent ACTION_DOWN
E/Debug: MyViewGroup2:super.onTouchEvent(event)false
E/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)false
E/Debug: MyViewGroup1:onTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:super.onTouchEvent(event)false
E/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)false
结论:在ViewGroup中onInterceptTouchEvent方法对事件传递进行拦截,返回值true代表不允许事件继续向子View传递,反之继续传递。
onTouchEvent方法
//MyView 中 onTouchEvent 返回 true
E/Debug: MyViewGroup1:dispatchTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_DOWN
E/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup2:dispatchTouchEvent ACTION_DOWN
E/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_DOWN
E/Debug: MyViewGroup2:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup3:dispatchTouchEvent ACTION_DOWN
E/Debug: MyViewGroup3:onInterceptTouchEvent ACTION_DOWN
E/Debug: MyViewGroup3:super.onInterceptTouchEvent(event)false
E/Debug: MyView:dispatchTouchEvent ACTION_DOWN
E/Debug: MyView:onTouchEvent ACTION_DOWN
E/Debug: MyView:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup3:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup1:dispatchTouchEvent ACTION_MOVE
E/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_MOVE
E/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup2:dispatchTouchEvent ACTION_MOVE
E/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_MOVE
E/Debug: MyViewGroup2:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup3:dispatchTouchEvent ACTION_MOVE
E/Debug: MyViewGroup3:onInterceptTouchEvent ACTION_MOVE
E/Debug: MyViewGroup3:super.onInterceptTouchEvent(event)false
E/Debug: MyView:dispatchTouchEvent ACTION_MOVE
E/Debug: MyView:onTouchEvent ACTION_MOVE
E/Debug: MyView:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup3:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup1:dispatchTouchEvent ACTION_UP
E/Debug: MyViewGroup1:onInterceptTouchEvent ACTION_UP
E/Debug: MyViewGroup1:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup2:dispatchTouchEvent ACTION_UP
E/Debug: MyViewGroup2:onInterceptTouchEvent ACTION_UP
E/Debug: MyViewGroup2:super.onInterceptTouchEvent(event)false
E/Debug: MyViewGroup3:dispatchTouchEvent ACTION_UP
E/Debug: MyViewGroup3:onInterceptTouchEvent ACTION_UP
E/Debug: MyViewGroup3:super.onInterceptTouchEvent(event)false
E/Debug: MyView:dispatchTouchEvent ACTION_UP
E/Debug: MyView:onTouchEvent ACTION_UP
E/Debug: MyView:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup3:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup2:super.dispatchTouchEvent(ev)true
E/Debug: MyViewGroup1:super.dispatchTouchEvent(ev)true
结论:如果这里把ViewGroup1或者2的onTouchEvent方法返回true,打印出来和上面的日志是一样的,why?这里需要借助源码解释了,只要被view消耗了onTouchEvent事件,那么ViewGroup将无法收到该事件.
眼过千遍不如手过一遍,看再多的理论自己实践才是王道.
小弟的功力有限,这里推荐郭霖大神分析源码地址:http://blog.csdn.net/guolin_blog/article/details/9097463