结论
dispatchTouchEvent、onTouchEvent中
ACTION_DOWN:返回true,说明当前View来处理事件,后续事件也要处理,事件不再向下传递;返回false,说明当前View不处理事件,后续事件直接由上一级View处理,当前View也不会再接收到后续事件
ACTION_MOVE、ACTION_UP:返回true,说明其子View已经接收了DOWN事件,这里返回true只会导致该部分事件不再继续向下传递(但也不会传递当前View的onTouchEvent处理),对于没有返回true的事件还按正常流程传递
onInterceptTouchEvent中
无论在什么时候拦截,接下来的事件都将传递给当前View的onTouchEvent来处理
注意
super.dispatchTouchEvent(event)的返回值取决于子View或当前View的onTouchEvent对应事件的返回值
测试代码
布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.cn.test.TextLinerLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.cn.test.TestButton
android:layout_width="200dp"
android:layout_height="200dp"
android:background="#f0f"/>
</com.cn.test.TextLinerLayout>
</LinearLayout>
TextLinerLayout中部分代码
public class TextLinerLayout extends LinearLayout {
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.d("liuyzz:TextLinerLayout:", "dispatchTouchEvent---");
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//dispatchTouchEvent 返回值在一定情况下取决于onTouchEvent的返回值
boolean b = super.dispatchTouchEvent(event);//这里只是调用下
Log.d("liuyzz:TextLinerLayout:", "dispatchTouchEvent---down=="+b);
return true;
case MotionEvent.ACTION_MOVE:
boolean b1 = super.dispatchTouchEvent(event);//这里只是调用下
Log.d("liuyzz:TextLinerLayout:", "dispatchTouchEvent---move=="+b1);
return true;
case MotionEvent.ACTION_UP:
Log.d("liuyzz:TextLinerLayout:", "dispatchTouchEvent---up");
break;
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.d("liuyzz:TextLinerLayout:", "onInterceptTouchEvent---");
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d("liuyzz:TextLinerLayout:", "onTouchEvent---");
return super.onTouchEvent(event);
}
}
TestButton部分代码
public class TestButton extends android.support.v7.widget.AppCompatButton {
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.d("liuyzz:button:", "dispatchTouchEvent---");
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
boolean b = super.onTouchEvent(event);//默认返回false
Log.d("liuyzz:button:", "onTouchEvent---down=="+b);
return true; //这里的返回值直接影响父View的super.dispatchTouchEvent(event)的返回值
case MotionEvent.ACTION_MOVE:
boolean b1 = super.onTouchEvent(event);//这里只是调用下
Log.d("liuyzz:button:", "onTouchEvent---move=="+b1);
return true; //这里的返回值直接影响父View的super.dispatchTouchEvent(event)的返回值
case MotionEvent.ACTION_UP:
Log.d("liuyzz:button:", "onTouchEvent---up");
break;
}
return super.onTouchEvent(event); //这里的返回值直接影响父View的super.dispatchTouchEvent(event)的返回值
}
}
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---
D/liuyzz:button:: dispatchTouchEvent---
D/liuyzz:button:: onTouchEvent---down==false//默认返回false
//这里的真假,取决于子View中down中返回的值
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---down==true
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---
D/liuyzz:button:: dispatchTouchEvent---
D/liuyzz:button:: onTouchEvent---move==false
//这里的真假,取决于子View中move中返回的值
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---move==true
.....
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---up
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---
D/liuyzz:button:: dispatchTouchEvent---
D/liuyzz:button:: onTouchEvent---up
由打印结果得知:TextLinerLayout的dispatchTouchEvent中调用super.dispatchTouchEvent方法,会执行onInterceptTouchEvent–>子View的dispatchTouchEvent–>子View的onTouchEvent,而返回值取决于自己或者子View的onTouchEvent的返回值
当把TextLinerLayout的dispatchTouchEvent的ACTION_DOWN事件返回false
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:button:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---
D/liuyzz:button:: dispatchTouchEvent---
D/liuyzz:button:: onTouchEvent---down==false
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---down==true
由打印结果得知(只打印以上日志,继续滑动也不会打印):ACTION_DOWN事件返回false则后续事件不会再分发给TextLinerLayout所以只会打印以上这些日志
当把TestButton中onTouchEvent方法中ACTION_DOWN事件返回false
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---
D/liuyzz:button:: dispatchTouchEvent---
D/liuyzz:button:: onTouchEvent---down==false
//因子View的down事件不处理,所以会调用父View的onTouchEvent
D/liuyzz:TextLinerLayout:: onTouchEvent---
//因为子View中onTouchEvent的DOWN中返回false,所以大部分情况下第8行的值取决于onTouchEvent的值
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---down==false
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
//执行第8行代码内部调用了onTouchEvent方法
D/liuyzz:TextLinerLayout:: onTouchEvent---
//因为子TextLinerLayout中onTouchEvent的返回默认值即false,所以大部分情况下第8行的值取决于onTouchEvent的值
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---move==false
.....
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: onTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---up
D/liuyzz:TextLinerLayout:: onTouchEvent---
由打印结果得知:子View在Down事件中不处理事件,将会上传给TextLinerLayout的onTouchEvent事件,并且后续事件不再会传递给子View
当把TestButton中onTouchEvent方法中ACTION_MOVE事件返回false
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---
D/liuyzz:button:: dispatchTouchEvent---
D/liuyzz:button:: onTouchEvent---down==false
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---down==true
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---
D/liuyzz:button:: dispatchTouchEvent---
D/liuyzz:button:: onTouchEvent---move==false
//这里的真假,取决于子View中move中返回的值
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---move==false
.....
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---up
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---
D/liuyzz:button:: dispatchTouchEvent---
D/liuyzz:button:: onTouchEvent---up
由打印结果得知:虽然button的move事件不处理事件,但事件流已经开始往button中传递了,所以返回true、false都会传递给子View
当TestButton中onTouchEvent方法中ACTION_MOVE事件返回false,TextLinerLayout中dispatchTouchEvent的ACTION_MOVE中返回false时##
打印结果和只是TestButton中onTouchEvent方法中ACTION_MOVE事件返回false的结果一样
当把TextLinerLayout的dispatchTouchEvent中的Down值修改如下
只返回true,而不再调用super.dispatchTouchEvent(event)
case MotionEvent.ACTION_DOWN:
Log.d("liuyzz:TextLinerLayout:", "dispatchTouchEvent---down");
return true;
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---down
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: onTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---move==false
.....
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---up
D/liuyzz:TextLinerLayout:: onTouchEvent---
由打印结果得知:在down中接收处理事件,则事件不会再往下传递到子View,也不会传递给自己的onInterceptTouchEvent、onTouchEvent方法,而在上面的move、up中进行了super.dispatchTouchEvent(event)调用,所以才会调用onTouchEvent方法
当把TextLinerLayout的dispatchTouchEvent中的值修改如下
case MotionEvent.ACTION_DOWN:
Log.d("liuyzz:TextLinerLayout:", "dispatchTouchEvent---down");
return true;
case MotionEvent.ACTION_MOVE:
Log.d("liuyzz:TextLinerLayout:", "dispatchTouchEvent---move");
return true;
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---down
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---move
.....
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---up
D/liuyzz:TextLinerLayout:: onTouchEvent---
由打印结果得知:把down、move都直接返回true时,onTouchEvent只会在up的时候被调用,因为默认up时会调用super.dispatchTouchEvent(event)
当把TextLinerLayout的dispatchTouchEvent中的Move值修改如下
只返回true,而不再调用super.dispatchTouchEvent(event)
case MotionEvent.ACTION_MOVE:
Log.d("liuyzz:TextLinerLayout:", "dispatchTouchEvent---move");
return true;
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---
D/liuyzz:button:: dispatchTouchEvent---
D/liuyzz:button:: onTouchEvent---down==false
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---down==true
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---move
.....
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---up
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---
D/liuyzz:button:: dispatchTouchEvent---
D/liuyzz:button:: onTouchEvent---up
由打印结果得知:只拦截了move事件,其他事件还是会传到button中处理,而TextLinerLayout的onToucheEvent并没有被调用,说明这只是拦截了事件,并不是拦下处理事件,由 此可以推出,当在父View的move或者up中返回true,则父View只拦截当前事件,后续事件不拦截会继续传递到子View
当把TextLinerLayout的dispatchTouchEvent中的值修改如下
case MotionEvent.ACTION_DOWN:
Log.d("liuyzz:TextLinerLayout:", "dispatchTouchEvent---down");
return break;
case MotionEvent.ACTION_MOVE:
Log.d("liuyzz:TextLinerLayout:", "dispatchTouchEvent---move");
return true;
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---down
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---
D/liuyzz:button:: dispatchTouchEvent---
D/liuyzz:button:: onTouchEvent---down==false
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---move
.....
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---up
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---
D/liuyzz:button:: dispatchTouchEvent---
D/liuyzz:button:: onTouchEvent---up
由打印结果得知:只拦截了move事件,其他事件还是会传到button中处理,而TextLinerLayout的onToucheEvent并没有被调用,说明这只是拦截了事件,并不是拦下处理事件,而在up中事件又传递到了onTouchEvent中,由 此可以推出,当在父View的move或者up中返回true,则父View只拦截当前事件,后续事件不拦截会继续传递到子View
当把onInterceptTouchEvent修改如下
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.d("liuyzz:TextLinerLayout:", "onInterceptTouchEvent---");
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("liuyzz:TextLinerLayout:", "onInterceptTouchEvent---down");
return true;
case MotionEvent.ACTION_MOVE:
Log.d("liuyzz:TextLinerLayout:", "onInterceptTouchEvent---move");
break;
case MotionEvent.ACTION_UP:
Log.d("liuyzz:TextLinerLayout:", "onInterceptTouchEvent---up");
break;
}
return super.onInterceptTouchEvent(ev);
}
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---down
//因为拦截了,所以直接调用自己的onTouchEvent
D/liuyzz:TextLinerLayout:: onTouchEvent---
//因为拦截了,所以这里的真假,取决于当前View的onTouchEvent中down中返回的值(默认返回false)
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---down==false
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: onTouchEvent---
//因为拦截了,所以这里的真假,取决于当前View的onTouchEvent中move中返回的值
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---move==false
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---up
D/liuyzz:TextLinerLayout:: onTouchEvent---
当把TextLinerLayout的dispatchTouchEvent中的值和onInterceptTouchEvent修改如下
case MotionEvent.ACTION_MOVE:
Log.d("liuyzz:TextLinerLayout:", "dispatchTouchEvent---move");
return true;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.d("liuyzz:TextLinerLayout:", "onInterceptTouchEvent---");
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("liuyzz:TextLinerLayout:", "onInterceptTouchEvent---down");
return true;
case MotionEvent.ACTION_MOVE:
Log.d("liuyzz:TextLinerLayout:", "onInterceptTouchEvent---move");
break;
case MotionEvent.ACTION_UP:
Log.d("liuyzz:TextLinerLayout:", "onInterceptTouchEvent---up");
break;
}
return super.onInterceptTouchEvent(ev);
}
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---down
D/liuyzz:TextLinerLayout:: onTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---down==false
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---move
.....
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---up
D/liuyzz:TextLinerLayout:: onTouchEvent---
由打印结果得知:当Move事件返回true,TextLinerLayout的onToucheEvent并没有被调用,说明这只是拦截了Move事件,并不是拦下处理事件,但因为onInterceptTouchEvent进行拦截,所以在up事件中不会再传递到子View中
当修改代码如下
case MotionEvent.ACTION_MOVE:
Log.d("liuyzz:TextLinerLayout:", "dispatchTouchEvent---move");
return true;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.d("liuyzz:TextLinerLayout:", "onInterceptTouchEvent---");
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("liuyzz:TextLinerLayout:", "onInterceptTouchEvent---down");
break;
case MotionEvent.ACTION_MOVE:
Log.d("liuyzz:TextLinerLayout:", "onInterceptTouchEvent---move");
return true;
case MotionEvent.ACTION_UP:
Log.d("liuyzz:TextLinerLayout:", "onInterceptTouchEvent---up");
break;
}
return super.onInterceptTouchEvent(ev);
}
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---down
D/liuyzz:button:: dispatchTouchEvent---
D/liuyzz:button:: onTouchEvent---down==false
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---down==true
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---move
.....
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---up
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---up
D/liuyzz:button:: dispatchTouchEvent---
D/liuyzz:button:: onTouchEvent---up
由打印结果得知:虽然在拦截的move中返回true,但是在dispatchTouchEvent的move中返回了true,因为不会走拦截中的move事件,即事件在dispatchTouchEvent的move中被拦截,但是并没有走到onTouchEvent中去处理,当up时,事件正常传递
当代码修改成在dispatchTouchEvent的move中使用break 如下
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.d("liuyzz:TextLinerLayout:", "dispatchTouchEvent---");
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("liuyzz:TextLinerLayout:", "dispatchTouchEvent---down");
break;
case MotionEvent.ACTION_MOVE:
Log.d("liuyzz:TextLinerLayout:", "dispatchTouchEvent---move");
break;
case MotionEvent.ACTION_UP:
Log.d("liuyzz:TextLinerLayout:", "dispatchTouchEvent---up");
break;
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
Log.d("liuyzz:TextLinerLayout:", "onInterceptTouchEvent---");
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.d("liuyzz:TextLinerLayout:", "onInterceptTouchEvent---down");
break;
case MotionEvent.ACTION_MOVE:
Log.d("liuyzz:TextLinerLayout:", "onInterceptTouchEvent---move");
return true;
case MotionEvent.ACTION_UP:
Log.d("liuyzz:TextLinerLayout:", "onInterceptTouchEvent---up");
break;
}
return super.onInterceptTouchEvent(ev);
}
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---down
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---down
D/liuyzz:button:: dispatchTouchEvent---
D/liuyzz:button:: onTouchEvent---down==false
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---move
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---
D/liuyzz:TextLinerLayout:: onInterceptTouchEvent---move
//不清楚这里为什么会只调用一次button方法
D/liuyzz:button:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---move
D/liuyzz:TextLinerLayout:: onTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---move
D/liuyzz:TextLinerLayout:: onTouchEvent---
.....
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---
D/liuyzz:TextLinerLayout:: dispatchTouchEvent---up
D/liuyzz:TextLinerLayout:: onTouchEvent---
由打印结果得知:虽然在move中进行拦截,但是还是会走一下button的dispatchTouchEvent的方法(不清楚为什么),但是button的onTouchEvent不会走,剩下的都会走TextLinerLayout的方法