首先我们的实例布局结构如下:
MyViewGroupA——最外层的ViewGroup
MyViewGroupB——中间的ViewGroup
MyView——最底层的View
代码非常简单只是重写了事件拦截和处理的几个方法,并给它加上一些Log而已
对于ViewGroup来说,重写了如下三个方法
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
Log.i(TAG, "dispatchTouchEvent: " + ev.getAction());
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.i(TAG, "onInterceptTouchEvent: " + ev.getAction());
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i(TAG, "onTouchEvent: " + event.getAction());
return super.onTouchEvent(event);
}
而对于View来说,重写了如下两个方法
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.i(TAG, "dispatchTouchEvent: " + event.getAction());
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i(TAG, "onTouchEvent: " + event.getAction());
return super.onTouchEvent(event);
}
ViewGroup级别比较高,比View多了一个方法——onInterceptTouchEvent()方法
首先我们不修改任何返回值,仅仅点击一下MyView,Log如下所示:
02-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyViewGroupA: dispatchTouchEvent: 0
02-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyViewGroupA: onInterceptTouchEvent: 0
02-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyViewGroupB: dispatchTouchEvent: 0
02-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyViewGroupB: onInterceptTouchEvent: 0
02-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyView: dispatchTouchEvent: 0
02-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyView: onTouchEvent: 0
02-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyViewGroupB: onTouchEvent: 0
02-05 18:20:32.291 10250-10250/com.example.customviewlayout I/MyViewGroupA: onTouchEvent: 0
可以看见,正常情况下,事件的传递顺序是:
MyViewGroupA->MyViewGroupB->MyView。事件传递的时候,执行dispatchTouchEvent()方法,再执行onInterceptTouchEvent()方法。
事件的处理顺序是:
MyView->MyViewGroupB->MyViewGroupA。事件处理都是执行onTouchEvent()方法。
事件传递的返回值非常容易理解:true,拦截,不继续;false,不拦截,继续流程。
事件处理的返回值也类似:true,处理了,不用审核了;false, 给父ViewGroup处理。
初始情况下,返回值都是false。
这里为了能够方便大家理解事件拦截的过程,在事件传递中,我们只关心onInterceptTouchEvent()方法,而dispatchTouchEvent()方法虽然是事件分发的第一步,但一般情况下,我们不太会去改写这个方法
这里让MyViewGroupA把事件拦截了,即让MyViewGroupA的onInterceptTouchEvent()方法返回true,Log如下:
02-05 19:09:48.220 16493-16493/com.example.customviewlayout I/MyViewGroupA: dispatchTouchEvent: 0
02-05 19:09:48.220 16493-16493/com.example.customviewlayout I/MyViewGroupA: onInterceptTouchEvent: 0
02-05 19:09:48.220 16493-16493/com.example.customviewlayout I/MyViewGroupA: onTouchEvent: 0
MyViewGroupA把事件拦截了,因此MyViewGroupB和MyView都接收不到事件了
下面让MyViewGroupB把事件拦截了,即让MyViewGroupB的onInterceptTouchEvent()方法返回true,Log如下:
02-05 19:11:13.240 16493-16493/com.example.customviewlayout I/MyViewGroupA: dispatchTouchEvent: 0
02-05 19:11:13.240 16493-16493/com.example.customviewlayout I/MyViewGroupA: onInterceptTouchEvent: 0
02-05 19:11:13.240 16493-16493/com.example.customviewlayout I/MyViewGroupB: dispatchTouchEvent: 0
02-05 19:11:13.240 16493-16493/com.example.customviewlayout I/MyViewGroupB: onInterceptTouchEvent: 0
02-05 19:11:13.240 16493-16493/com.example.customviewlayout I/MyViewGroupB: onTouchEvent: 0
02-05 19:11:13.240 16493-16493/com.example.customviewlayout I/MyViewGroupA: onTouchEvent: 0
MyViewGroupB把事件拦截了,因此MyView接收不到事件了
在事件的处理中,事件分发到MyView然后它处理完事件,需要向父布局报告,所以MyView的事件处理返回false,但若MyView的onTouchEvent()方法返回true时,Log日志如下:
02-05 19:53:53.730 30716-30716/com.example.customviewlayout I/MyViewGroupA: dispatchTouchEvent: 0
02-05 19:53:53.730 30716-30716/com.example.customviewlayout I/MyViewGroupA: onInterceptTouchEvent: 0
02-05 19:53:53.730 30716-30716/com.example.customviewlayout I/MyViewGroupB: dispatchTouchEvent: 0
02-05 19:53:53.730 30716-30716/com.example.customviewlayout I/MyViewGroupB: onInterceptTouchEvent: 0
02-05 19:53:53.730 30716-30716/com.example.customviewlayout I/MyView: dispatchTouchEvent: 0
02-05 19:53:53.730 30716-30716/com.example.customviewlayout I/MyView: onTouchEvent: 0
可以看见,事件传递和以前一样,但是事件处理,到MyView这里就结束了,因为MyView返回true,表示不用向父布局汇报了。
注:设为false时只能监听到值为0的down事件,设为true时就能监听到值为1或2的move up等等其它事件
如果MyView返回了false,MyViewGroupB想拦截这个事件,于是将onTouchEvent()方法返回true,那整个事件也就到此为止了,Log如下:
02-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyViewGroupA: dispatchTouchEvent: 0
02-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyViewGroupA: onInterceptTouchEvent: 0
02-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyViewGroupB: dispatchTouchEvent: 0
02-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyViewGroupB: onInterceptTouchEvent: 0
02-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyView: dispatchTouchEvent: 0
02-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyView: onTouchEvent: 0
02-05 19:59:54.180 30716-30716/com.example.customviewlayout I/MyViewGroupB: onTouchEvent: 0
注:在ViewGroup中设为true时同样就能监听到值为1或2的move up等等其它事件
通过以上几种情况相信大家能比较容易的了解事件的分发、拦截、处理事件的流程了。