你真的理解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事件分发机制就聊到这里,有人会说你为什么不从源码角度去分析下,我想说的是这个东西本来就很多坑了,你这个时候记住了,用的时候可能又会忘了,知道怎么用就好,再分析下源码,估计头更大了,如有问题,欢迎指正,谢谢。
- 你真的理解android事件分发机制了吗
- 教你彻底理解Android的事件分发机制
- 关于Android事件分发机制的理解
- Android事件分发机制的理解
- Android事件分发机制的理解
- Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
- Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
- Android事件分发机制完全解析,带你从源码的角度彻底理解(下)
- Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
- Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
- Android事件分发机制完全解析,带你从源码的角度彻底理解
- Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
- Android事件分发机制完全解析,带你从源码的角度彻底理解(下)
- Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
- Android事件分发机制完全解析,带你从源码的角度彻底理解(下)
- Android事件分发机制完全解析,带你从源码的角度彻底理解(上)
- Android事件分发机制完全解析,带你从源码的角度彻底理解(下)
- Android事件分发机制完全解析,带你从源码的角度彻底理解(下) 。
- java中HashMap,LinkedHashMap,TreeMap,HashTable的区别
- Swift - 文本框textView图文混排的实现(附样例)
- 《程序员的思维修炼》读书笔记以及感悟
- javascript DOM操作
- git 命令
- 你真的理解android事件分发机制了吗
- 使用ionic开发移动app的过程中经验总结
- Phoenix默认jvm配置
- func_get_args的使用
- libc++abi.dylib`__cxa_throw: 使用[AVAudioPlayer play]会产生__cxa_throw异常
- iOS开发 适配iOS10以及Xcode8
- cordova创建第一个iOS程序实例
- 自定义scrollView实现顶部图片下拉放大
- java 字节流和字符流的区别 转载