你真的理解android事件分发机制了吗

来源:互联网 发布:中建六局 知乎 编辑:程序博客网 时间:2024/05/16 16:07

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

0 0
原创粉丝点击