最近在看一些源代码的时候,又遇到了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_DOWNE/fuqiang: MyTestView ---onTouch -- ACTION_DOWNE/fuqiang: MyTestView ---onTouchEvent -- ACTION_DOWNE/fuqiang: MyTestView ---onLongClickE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_UPE/fuqiang: MyTestView ---onTouch -- ACTION_UPE/fuqiang: MyTestView ---onTouchEvent -- ACTION_UPE/fuqiang: MyTestView ---onClick

以此执行了dispatchTouchEvent,onTouch,onTouchEvent ,onLongClick,onClick,这里我们要注意
onTouch是在onTouchEvent 前执行的,然后执行了长按onLongClick,最后当手抬起的时候,才会执行onClick。
接下来我们第二个操作,点击TextView,移动,然后松开:

E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_DOWNE/fuqiang: MyTestView ---onTouch -- ACTION_DOWNE/fuqiang: MyTestView ---onTouchEvent -- ACTION_DOWNE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---onTouch -- ACTION_MOVEE/fuqiang: MyTestView ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---onTouch -- ACTION_MOVEE/fuqiang: MyTestView ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---onTouch -- ACTION_MOVEE/fuqiang: MyTestView ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_UPE/fuqiang: MyTestView ---onTouch -- ACTION_UPE/fuqiang: MyTestView ---onTouchEvent -- ACTION_UPE/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_DOWNE/fuqiang: MyTestView ---onTouch -- ACTION_DOWNE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---onTouch -- ACTION_MOVEE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---onTouch -- ACTION_MOVEE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---onTouch -- ACTION_MOVEE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---onTouch -- ACTION_MOVEE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---onTouch -- ACTION_MOVEE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---onTouch -- ACTION_MOVEE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---onTouch -- ACTION_MOVEE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_UPE/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_DOWNE/fuqiang: MyTestView ---onTouch -- ACTION_DOWNE/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_DOWNE/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_DOWNE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_DOWNE/fuqiang: MyTestView ---onTouch -- ACTION_DOWNE/fuqiang: MyTestView ---onTouchEvent -- ACTION_DOWNE/fuqiang: MyLinearLayout ---onTouch -- ACTION_DOWNE/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_DOWNE/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_DOWNE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_DOWNE/fuqiang: MyTestView ---onTouch -- ACTION_DOWNE/fuqiang: MyTestView ---onTouchEvent -- ACTION_DOWNE/fuqiang: MyLinearLayout ---onTouch -- ACTION_DOWNE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_DOWNE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_UPE/fuqiang: MyLinearLayout ---onTouch -- ACTION_UPE/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_DOWNE/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_DOWNE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_DOWNE/fuqiang: MyTestView ---onTouch -- ACTION_DOWNE/fuqiang: MyTestView ---onTouchEvent -- ACTION_DOWNE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---onTouch -- ACTION_MOVEE/fuqiang: MyTestView ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---onTouch -- ACTION_MOVEE/fuqiang: MyTestView ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---onTouch -- ACTION_MOVEE/fuqiang: MyTestView ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_UPE/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_UPE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_UPE/fuqiang: MyTestView ---onTouch -- ACTION_UPE/fuqiang: MyTestView ---onTouchEvent -- ACTION_UP

可以看到子类消费了接下来的事件,onInterceptTouchEvent 每次还会执行,因为是对子类的分发,最后执行完并不会再回到父类,因为自己已经把剩余事件给消费了。
接下来我们代码不动,进行另外一种操作,我在TextView之外的区域,点击,移动,抬起,执行结果如下:

E/fuqiang: MyLinearLayoutE/fuqiang: MyTestViewE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_DOWNE/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_DOWNE/fuqiang: MyLinearLayout ---onTouch -- ACTION_DOWNE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_DOWNE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_UPE/fuqiang: MyLinearLayout ---onTouch -- ACTION_UPE/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_DOWNE/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_DOWNE/fuqiang: MyLinearLayout ---onTouch -- ACTION_DOWNE/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_DOWNE/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_DOWNE/fuqiang: MyLinearLayout ---onTouch -- ACTION_DOWNE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_DOWNE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_UPE/fuqiang: MyLinearLayout ---onTouch -- ACTION_UPE/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_DOWNE/fuqiang: MyLinearLayout ---onInterceptTouchEvent -- ACTION_DOWNE/fuqiang: requestDisallowInterceptTouchEvent E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_DOWNE/fuqiang: MyTestView ---onTouch -- ACTION_DOWNE/fuqiang: MyTestView ---onTouchEvent -- ACTION_DOWNE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---onTouch -- ACTION_MOVEE/fuqiang: MyTestView ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---onTouch -- ACTION_MOVEE/fuqiang: MyTestView ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyTestView ---onTouch -- ACTION_MOVEE/fuqiang: MyTestView ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_UPE/fuqiang: requestDisallowInterceptTouchEvent E/fuqiang: MyTestView ---dispatchTouchEvent -- ACTION_UPE/fuqiang: MyTestView ---onTouch -- ACTION_UPE/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_DOWNE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouch -- ACTION_MOVEE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_MOVEE/fuqiang: MyLinearLayout ---dispatchTouchEvent -- ACTION_UPE/fuqiang: MyLinearLayout ---onTouch -- ACTION_UPE/fuqiang: MyLinearLayout ---onTouchEvent -- ACTION_UP

可以看到dispatchTouchEvent 监听完DOWN之后,DOWN就此结束了,onInterceptTouchEvent 和onTouch ,onTouchEvent 都没有监听Down了,并且后续的移动和抬起onInterceptTouchEvent 也不执行了,而是父类的dispatchTouchEvent ,onTouch ,onTouchEvent 依次执行。

好了,android事件分发机制就聊到这里,有人会说你为什么不从源码角度去分析下,我想说的是这个东西本来就很多坑了,你这个时候记住了,用的时候可能又会忘了,知道怎么用就好,再分析下源码,估计头更大了,如有问题,欢迎指正,谢谢。

更多相关文章

  1. android(基于回调)的事件处理
  2. android 存储操作 大小显示换算 kb mb KB MB 读取
  3. android 开发使用 kotlin 进行点击事件监听和界面跳转,直接传也方
  4. android 下Excel操作
  5. Android使用EventBus传递事件
  6. mono android 非UI线程操作UI线程
  7. 操作内存卡的常用代码
  8. android 按钮的四种点击事件

随机推荐

  1. Android(安卓)7.1 导航栏增加按键, 关机
  2. android Studio遇到transformClassesWith
  3. Androud 如何区分USB设备
  4. Android(安卓)PopupWindow 使点击区域外
  5. Android(安卓)Studio 4.0 新功能之Live L
  6. 仿写Arouter框架实现Activity的跳转
  7. Android获取控件的大小
  8. Gradle设置代码混淆
  9. Android(安卓)输入框弹出样式
  10. Android(安卓)自定义titlebar控件(自定义U