这一块的东西比较理解起来比较费劲,自己也是断断续续学习理解了三四次,才有点儿眉目。写出来,各位大神提点儿建议,助我爬坑。
测试代码,就是一个继承 Linearlayout 的父控件,重写onInterceptTouchEvent 和 onTouchEvent,然后就是一个继承 TextView 的子View 和一个继承 Button 的子View,两个子View 重写 onTouchEvent 方法。很简单,我在这儿就不贴了。
gif1
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
我们直接贴 Log.
onInterceptTouchEvent ACTION_DOWN
MyTextView ACTION_DOWN
parent ACTION_DOWN
只是触发了 Down 事件。为了方便大家理解,我们再画图描述一下。
结果与TextView 是一样的。
12-06 15:17:11.307 23478-23478/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_DOWN
12-06 15:17:11.308 23478-23478/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_DOWN
12-06 15:17:11.330 23478-23478/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_MOVE
12-06 15:17:11.331 23478-23478/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_MOVE
12-06 15:17:17.346 23478-23478/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_MOVE
12-06 15:17:17.346 23478-23478/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_MOVE
12-06 15:17:17.361 23478-23478/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_MOVE
12-06 15:17:17.361 23478-23478/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_MOVE
12-06 15:17:17.362 23478-23478/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_UP
12-06 15:17:17.362 23478-23478/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_UP
12-06 15:17:17.363 23478-23478/com.example.shoppingchen.touchdemo V/wangcong: dan ji le
我们发现有些许的不一样了。 down move up 事件全部传递给了子View,但是没有调用父容器的 onTouchEvent 方法。
发现结果和 2.1.3 是完全一样的(除了没有打出 dan ji le 字样)
所以,我们得出第一个结论:
结论1:消费事件的方法有两个,1、注册单击、长按等事件;2、onTouchEvent 返回 true。
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
i=0;
android.util.Log.v("wangcong","onInterceptTouchEvent ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
i++;
// 在第三次传递 move 事件之后,我们进行拦截
if(i > 3){
return true;
}
android.util.Log.v("wangcong","onInterceptTouchEvent ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
android.util.Log.v("wangcong","onInterceptTouchEvent ACTION_UP");
break;
}
return super.onInterceptTouchEvent(ev);
}
看log:
12-06 15:41:18.420 2946-2946/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_DOWN
12-06 15:41:18.420 2946-2946/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_DOWN
12-06 15:41:18.438 2946-2946/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_MOVE
12-06 15:41:18.438 2946-2946/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_MOVE
12-06 15:41:18.455 2946-2946/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_MOVE
12-06 15:41:18.455 2946-2946/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_MOVE
12-06 15:41:18.488 2946-2946/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_MOVE
12-06 15:41:18.488 2946-2946/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_MOVE
12-06 15:41:18.505 2946-2946/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_CANCEL
12-06 15:41:18.523 2946-2946/com.example.shoppingchen.touchdemo V/wangcong: parent ACTION_MOVE
12-06 15:41:18.539 2946-2946/com.example.shoppingchen.touchdemo V/wangcong: parent ACTION_MOVE
12-06 15:41:18.555 2946-2946/com.example.shoppingchen.touchdemo V/wangcong: parent ACTION_MOVE
12-06 15:41:18.572 2946-2946/com.example.shoppingchen.touchdemo V/wangcong: parent ACTION_MOVE
12-06 15:41:18.572 2946-2946/com.example.shoppingchen.touchdemo V/wangcong: parent ACTION_UP
子View在接收三条 move 事件之后,就没有再接收到事件,拦截成功了。所以得出结论2.
结论2:在 onTouchEvent() 方法中拦截之后,其余事件就会一直继续被 该View 处理,除非上层拦截(即使你返回true,表示要处理这些事件,但是这些事件终究要通过上层传递给你,就是每次都要经过 onInterceptTouchEvent ,上层还是可以拦截)。
12-06 15:50:48.247 3975-3975/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_DOWN
12-06 15:50:48.248 3975-3975/com.example.shoppingchen.touchdemo V/wangcong: parent ACTION_DOWN
在这个时候,我们称之为容器的 View,其实就和我们的 Button 和 TextView 没有什么区别了。
那么得出结论:
结论3: 事件传递层次位置由 Down 事件确定,这就意味着只有与你按下位置相关的控件才有可能接收到事件,无关的绝对不可能接收到事件(除非你自己重新定义事件传递)。
结论4:所有这些控件都是继承 View,本质都是一样的。
父容器不拦截,子控件消费 Down 事件,消费 3 个move 事件之后,返回false,不消费了。
12-06 16:06:35.097 13085-13085/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_DOWN
12-06 16:06:35.098 13085-13085/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_DOWN
12-06 16:06:35.108 13085-13085/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_MOVE
12-06 16:06:35.108 13085-13085/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_MOVE
12-06 16:06:35.142 13085-13085/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_MOVE
12-06 16:06:35.142 13085-13085/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_MOVE
12-06 16:06:35.158 13085-13085/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_MOVE
12-06 16:06:35.159 13085-13085/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_MOVE
12-06 16:06:35.192 13085-13085/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_MOVE
12-06 16:06:37.309 13085-13085/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_MOVE
12-06 16:06:37.326 13085-13085/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_MOVE
12-06 16:06:37.358 13085-13085/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_MOVE
12-06 16:06:37.361 13085-13085/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_UP
12-06 16:06:37.361 13085-13085/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_UP
我们看 log 发现,Move 事件接收了三个,但是up 事件还是传到了 子View 中。
得出结论:
结论5:down 返回false,则其它事件都不会再接收,down 事件返回true,即使 move 事件返回 false,也会接收到其他事件。
我们修改容器onTouchEvent 方法,down 返回false,move 返回 true。 试一下
12-06 16:21:11.042 16510-16510/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_DOWN
12-06 16:21:11.043 16510-16510/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_DOWN
12-06 16:21:11.084 16510-16510/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_MOVE
12-06 16:21:11.085 16510-16510/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_MOVE
12-06 16:21:11.118 16510-16510/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_MOVE
12-06 16:21:11.118 16510-16510/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_MOVE
12-06 16:21:11.134 16510-16510/com.example.shoppingchen.touchdemo V/wangcong: onInterceptTouchEvent ACTION_MOVE
12-06 16:21:11.134 16510-16510/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_MOVE
12-06 16:21:11.150 16510-16510/com.example.shoppingchen.touchdemo V/wangcong: MyButtonView ACTION_CANCEL
12-06 16:21:11.167 16510-16510/com.example.shoppingchen.touchdemo V/wangcong: parent ACTION_MOVE
12-06 16:21:11.184 16510-16510/com.example.shoppingchen.touchdemo V/wangcong: parent ACTION_MOVE
12-06 16:21:11.200 16510-16510/com.example.shoppingchen.touchdemo V/wangcong: parent ACTION_MOVE
12-06 16:21:11.217 16510-16510/com.example.shoppingchen.touchdemo V/wangcong: parent ACTION_MOVE
12-06 16:21:11.234 16510-16510/com.example.shoppingchen.touchdemo V/wangcong: parent ACTION_MOVE
12-06 16:21:11.246 16510-16510/com.example.shoppingchen.touchdemo V/wangcong: parent ACTION_MOVE
12-06 16:21:11.246 16510-16510/com.example.shoppingchen.touchdemo V/wangcong: parent ACTION_UP
从 log 中看出,先是 子 View down 事件返回 true , 表示要处理事件,接收四个 move 事件之后,父容器拦截了事件,然后父容器的 onTouchEvent 接收到事件,最终也接收到了Up事件。得出结论:
结论6:父容器可以拦截已经被子View 确定要处理的 事件,自己来处理。
答案肯定是不行的,我们继续看 3.2 中的log,当父容器的 onTouchEvent 返回 true 决定处理后续事件之后,
onInterceptTouchEvent 没有再执行。
得出结论:
结论7:父容器能够给子容器擦屁股,但是子容器无法给父容器擦屁股。(话糙理不糙哈。)
这就是我对事件传递的一些理解了。
为什么要写这篇博客呢,因为感觉自己理解了和能否给别人讲清楚是两回事儿。如果有什么写的不对的地方,希望大家批评指正。