最近在看一些源代码的时候,又遇到了android的事件分发机制,以前我以为我懂了,但是看着看着又糊涂了,于上浏览了下别人写的文章,越看越糊涂,干脆自己写个程序验证下,这一验证,才发现以前没有真正懂这个流程,今天我就用事实说话,来跟大家一起验证下android的事件分发机制(很多坑需要注意):
事件分发中我们无非会遇到这么几个函数,dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent,onTouch,onClick,onLongClick,先从一个简单的View说起,然后再给这个View外面嵌套一个ViewGroup:
一 先看一个简单的View:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.fq.myviewgroup.MainActivity">
<com.fq.myviewgroup.MyTestView android:layout_width="match_parent" android:layout_height="200dp" android:text="Hello World!" android:layout_gravity="center" android:gravity="center" android:background="#123321"/>
</LinearLayout>
package com.fq.myviewgroup;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
/** * Created by fq on 2016/9/21. */
public class MyTestView extends TextView implements View.OnClickListener,View.OnLongClickListener,View.OnTouchListener{
public static final String TAG = "fuqiang";
public MyTestView(Context context, AttributeSet attrs) {
super(context, attrs);
Log.e(TAG, "MyTestView");
setOnClickListener(this);
setOnLongClickListener(this);
setOnTouchListener(this);
}
@Override
public void onClick(View v) {
Log.e(TAG,"MyTestView ---onClick");
}
@Override
public boolean onLongClick(View v) {
Log.e(TAG,"MyTestView ---onLongClick");
return false;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
Log.e(TAG,"MyTestView ---dispatchTouchEvent -- ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG,"MyTestView ---dispatchTouchEvent -- ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG,"MyTestView ---dispatchTouchEvent -- ACTION_UP");
break;
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
Log.e(TAG,"MyTestView ---onTouchEvent -- ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG,"MyTestView ---onTouchEvent -- ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG,"MyTestView ---onTouchEvent -- ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
Log.e(TAG,"MyTestView ---onTouch -- ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG,"MyTestView ---onTouch -- ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG,"MyTestView ---onTouch -- ACTION_UP");
break;
}
return false;
}
}
好了,程序很简单,在各个touch函数打印了相关log,下面我们先来做第一个操作,点击TextView,长按,然后松开,执行结果如下:
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_DOWN
E/fuqiang: MyTestView ---onTouch -- ACTION_DOWN
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_DOWN
E/fuqiang: MyTestView ---onLongClick
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_UP
E/fuqiang: MyTestView ---onTouch -- ACTION_UP
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_UP
E/fuqiang: MyTestView ---onClick
以此执行了dispatchTouchEvent,onTouch,onTouchEvent ,onLongClick,onClick,这里我们要注意
onTouch是在onTouchEvent 前执行的,然后执行了长按onLongClick,最后当手抬起的时候,才会执行onClick。
接下来我们第二个操作,点击TextView,移动,然后松开:
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_DOWN
E/fuqiang: MyTestView ---onTouch -- ACTION_DOWN
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_DOWN
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouch -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouch -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouch -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_UP
E/fuqiang: MyTestView ---onTouch -- ACTION_UP
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_UP
E/fuqiang: MyTestView ---onClick
也很清晰,只是长按没有了而已,接下来我们对代码进行一些改动,让onTouch返回true:
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
Log.e(TAG,"MyTestView ---onTouch -- ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG,"MyTestView ---onTouch -- ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG,"MyTestView ---onTouch -- ACTION_UP");
break;
}
return true;
}
接下来点击,移动,松开:
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_DOWN
E/fuqiang: MyTestView ---onTouch -- ACTION_DOWN
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouch -- ACTION_MOVE
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouch -- ACTION_MOVE
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouch -- ACTION_MOVE
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouch -- ACTION_MOVE
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouch -- ACTION_MOVE
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouch -- ACTION_MOVE
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouch -- ACTION_MOVE
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_UP
E/fuqiang: MyTestView ---onTouch -- ACTION_UP
可以看到onTouchEvent 没有被执行了,这是为什么呢,看下dispatchTouchEvent 的源码:
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
如果onTouch的返回值是true,直接返回了,不继续执行onTouchEvent了。
看另外一个坑,现在把如下代码注释掉:
// setOnClickListener(this);
// setOnLongClickListener(this);
再次按下,移动,松开:
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_DOWN
E/fuqiang: MyTestView ---onTouch -- ACTION_DOWN
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_DOWN
移动和抬起全都没有监听到了,这是为什么呢,查看源码发现,设置上面这两句会使onTouchEvent的返回值为true,onTouchEvent的返回值为true才会消费接下来的一系列事件,如果是默认(false),是不会继续消费移动和抬起事件的。
好了,接下来我给这个TextView外面再套一层我写的ViewGroup,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<com.fq.myviewgroup.MyLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.fq.myviewgroup.MainActivity">
<com.fq.myviewgroup.MyTestView
android:layout_width="match_parent"
android:layout_height="200dp"
android:text="Hello World!"
android:layout_gravity="center"
android:gravity="center"
android:background="#123321"/>
</com.fq.myviewgroup.MyLinearLayout>
package com.fq.myviewgroup;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
/** * Created by fq on 2016/9/21. */
public class MyLinearLayout extends LinearLayout implements View.OnClickListener,View.OnLongClickListener,View.OnTouchListener{
public static final String TAG = "fuqiang";
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
Log.e(TAG , "MyLinearLayout");
// setOnClickListener(this);
// setOnLongClickListener(this);
setOnTouchListener(this);
}
@Override
public void onClick(View v) {
Log.e(TAG,"MyLinearLayout ---onClick");
}
@Override
public boolean onLongClick(View v) {
Log.e(TAG,"MyLinearLayout ---onLongClick");
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
Log.e(TAG,"MyLinearLayout ---onInterceptTouchEvent -- ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG,"MyLinearLayout ---onInterceptTouchEvent -- ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG,"MyLinearLayout ---onInterceptTouchEvent -- ACTION_UP");
break;
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
Log.e(TAG,"MyLinearLayout ---dispatchTouchEvent -- ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG,"MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG,"MyLinearLayout ---dispatchTouchEvent -- ACTION_UP");
break;
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
Log.e(TAG,"MyLinearLayout ---onTouchEvent -- ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG,"MyLinearLayout ---onTouchEvent -- ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG,"MyLinearLayout ---onTouchEvent -- ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
Log.e(TAG,"MyLinearLayout ---onTouch -- ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG,"MyLinearLayout ---onTouch -- ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG,"MyLinearLayout ---onTouch -- ACTION_UP");
break;
}
return false;
}
@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept)
{
Log.e(TAG, "requestDisallowInterceptTouchEvent ");
super.requestDisallowInterceptTouchEvent(disallowIntercept);
}
}
也很简单,就是打印了关键函数的一些log,onClick和onLongClick刚才分析过了,这里直接注释掉,不解释了,接下来,我依然在TextView这个区域按下,移动,抬起,执行结果如下:
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_DOWN
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_DOWN
E/fuqiang: MyTestView ---onTouch -- ACTION_DOWN
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_DOWN
执行次序,父类的dispatchTouchEvent ,onInterceptTouchEvent ,子类的dispatchTouchEvent ,onTouch ,onTouchEvent ,然后又重新回到父类的onTouch ,onTouchEvent ,并且只监听了ACTION_DOWN,移动和抬起事件没人管了,这是为什么,因为无论是父类还是子类,onTouchEvent 默认都返回的false,也就是说都不管接下来发生的事,按下事件从父类传到子类,又从子类传到父类,没人愿意管,好,下面我们修改父类的onTouchEvent ,让它返回true:
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
Log.e(TAG,"MyLinearLayout ---onTouchEvent -- ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG,"MyLinearLayout ---onTouchEvent -- ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG,"MyLinearLayout ---onTouchEvent -- ACTION_UP");
break;
}
return true;
}
然后再按下,移动,抬起,执行结果:
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_DOWN
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_DOWN
E/fuqiang: MyTestView ---onTouch -- ACTION_DOWN
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_UP
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_UP
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_UP
可以看到先执行父类的dispatchTouchEvent ,onInterceptTouchEvent ,然后传到子类,发现子类的onTouchEvent 返回false,表示他不打算管,然后又传回给父类onTouchEvent ,父类onTouchEvent 返回true了,表示要管,所以接下来的移动和抬起事件都传递给父类的dispatchTouchEvent ,onTouch ,onTouchEvent 方法,这时不会再传递给onInterceptTouchEvent ,onInterceptTouchEvent 只负责对子类的分发。
接下来我把子类的onTouchEvent返回值改成True:
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
Log.e(TAG,"MyTestView ---onTouchEvent -- ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG,"MyTestView ---onTouchEvent -- ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG,"MyTestView ---onTouchEvent -- ACTION_UP");
break;
}
return true;
}
然后,按下,移动,抬起:
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_DOWN
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_DOWN
E/fuqiang: MyTestView ---onTouch -- ACTION_DOWN
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouch -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouch -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouch -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_UP
E/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_UP
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_UP
E/fuqiang: MyTestView ---onTouch -- ACTION_UP
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_UP
可以看到子类消费了接下来的事件,onInterceptTouchEvent 每次还会执行,因为是对子类的分发,最后执行完并不会再回到父类,因为自己已经把剩余事件给消费了。
接下来我们代码不动,进行另外一种操作,我在TextView之外的区域,点击,移动,抬起,执行结果如下:
E/fuqiang: MyLinearLayout
E/fuqiang: MyTestView
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_UP
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_UP
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_UP
可以看到,并没有分发给子类,而是自己消费了,是因为按下的区域并没有找到子View,那如果我把父类的onTouchEvent返回值改成默认呢?:
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
Log.e(TAG,"MyLinearLayout ---onTouchEvent -- ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG,"MyLinearLayout ---onTouchEvent -- ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG,"MyLinearLayout ---onTouchEvent -- ACTION_UP");
break;
}
return super.onTouchEvent(event);
}
在同样在TextView之外的区域按下,移动,抬起
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_DOWN
由于这个父类onTouchEvent返回值是默认(false),他不打算管接下来的事件,所以就只监听到Down事件了。
接下来我来修改onInterceptTouchEvent,让ACTION_DOWN的时候直接返回true:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
Log.e(TAG,"MyLinearLayout ---onInterceptTouchEvent -- ACTION_DOWN");
return true;
case MotionEvent.ACTION_MOVE:
Log.e(TAG,"MyLinearLayout ---onInterceptTouchEvent -- ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG,"MyLinearLayout ---onInterceptTouchEvent -- ACTION_UP");
break;
}
return super.onInterceptTouchEvent(ev);
}
然后在TextView所在区域按下,移动,抬起:
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_UP
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_UP
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_UP
可以看到,父类拦截了接下来的所有操作,并没有传递给子类,我们如果想让父类拦截,在onInterceptTouchEvent按下,移动和抬起事件返回true即可,但是如果明明被拦截了,子类依然想执行怎么办,getParent().requestDisallowInterceptTouchEvent(true),这样调用即可,之前父类的拦截就失效了,但是只能在onInterceptTouchEvent的移动事件ACTION_MOVE之后返回true才行,在ACTION_DOWN里返回true,子类这样写不起作用:
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);
Log.e(TAG,"MyTestView ---dispatchTouchEvent -- ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.e(TAG,"MyTestView ---dispatchTouchEvent -- ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
getParent().requestDisallowInterceptTouchEvent(false);
Log.e(TAG,"MyTestView ---dispatchTouchEvent -- ACTION_UP");
break;
}
return super.dispatchTouchEvent(event);
}
再按下,移动,抬起,如下:
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_DOWN
E/fuqiang: requestDisallowInterceptTouchEvent
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_DOWN
E/fuqiang: MyTestView ---onTouch -- ACTION_DOWN
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouch -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouch -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouch -- ACTION_MOVE
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_UP
E/fuqiang: requestDisallowInterceptTouchEvent
E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_UP
E/fuqiang: MyTestView ---onTouch -- ACTION_UP
E/fuqiang: MyTestView ---onTouchEvent -- ACTION_UP
我们看到父类的拦截不起作用了,子类仍然可以监听到后续的操作。
来说最后一个,如果我在父类的dispatchTouchEvent里返回true会怎么样呢:
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
Log.e(TAG,"MyLinearLayout ---dispatchTouchEvent -- ACTION_DOWN");
return true;
case MotionEvent.ACTION_MOVE:
Log.e(TAG,"MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.e(TAG,"MyLinearLayout ---dispatchTouchEvent -- ACTION_UP");
break;
}
return super.dispatchTouchEvent(ev);
}
在case MotionEvent.ACTION_DOWN:的时候返回了true,依然是按下,移动,抬起:
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_DOWN
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVE
E/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_UP
E/fuqiang: MyLinearLayout ---onTouch -- ACTION_UP
E/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_UP
可以看到dispatchTouchEvent 监听完DOWN之后,DOWN就此结束了,onInterceptTouchEvent 和onTouch ,onTouchEvent 都没有监听Down了,并且后续的移动和抬起onInterceptTouchEvent 也不执行了,而是父类的dispatchTouchEvent ,onTouch ,onTouchEvent 依次执行。
好了,android事件分发机制就聊到这里,有人会说你为什么不从源码角度去分析下,我想说的是这个东西本来就很多坑了,你这个时候记住了,用的时候可能又会忘了,知道怎么用就好,再分析下源码,估计头更大了,如有问题,欢迎指正,谢谢。