android 事件分发机制
Posted luzhouxiaoshuai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android 事件分发机制相关的知识,希望对你有一定的参考价值。
我们通过代码来分析
package im.weiyuan.com.viewutils; import android.content.Intent; import android.os.PersistableBundle; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private MyView view; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); view = (MyView) findViewById(R.id.view_main); /** * 设置touch监听事件 * */ view.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) {
Log.d("123456","MyView setOnTouchListener is called "); return false; } }); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.d("123456","activity dispatchTouchEvent is called" +ev.getAction()); return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d("123456","activity onTouchEvent is called"+event.getAction()); return super.onTouchEvent(event); } }
package im.weiyuan.com.viewutils; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; /** * Created by wei.yuan on 2017/7/24. */ public class MyView extends ImageView { public MyView(Context context) { super(context); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public MyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.d("123456","MyView dispatchTouchEvent is called"+event.getAction()); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d("123456","MyView onTouchEvent is called"+event.getAction()); return super.onTouchEvent(event); } }
<?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:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="im.weiyuan.com.viewutils.MainActivity"> <im.weiyuan.com.viewutils.MyView android:text="点击" android:src="@mipmap/ic_launcher" android:id="@+id/view_main" android:layout_width="100dp" android:layout_height="100dp" /> </LinearLayout>
我们来进行下面的测试环境的操作:
1、点击activity的页面,不点击图片,只点击activity
07-24 11:29:59.882 16649-16649/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called0
07-24 11:29:59.882 16649-16649/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called0
07-24 11:29:59.889 16649-16649/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:29:59.889 16649-16649/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called2
07-24 11:29:59.911 16649-16649/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:29:59.911 16649-16649/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called2
07-24 11:29:59.930 16649-16649/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:29:59.930 16649-16649/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called2
07-24 11:29:59.937 16649-16649/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:29:59.938 16649-16649/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called2
07-24 11:29:59.938 16649-16649/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called1
07-24 11:29:59.938 16649-16649/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called1
日志的打印上面所示:
首先调用activity dispatchTouchEvent is called0 0表示手指按下 2表示手指移动,1表示手指抬起
dispatchTouchEvent会调用对应的activity的dispatchTouchEvent来分发事件
onTouchEvent 用来处理分发的事件
2、下面我们来进行下面的操作,我们点击图片,我们来看看日志打印
07-24 11:39:22.171 28610-28610/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called0
07-24 11:39:22.172 28610-28610/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called0
07-24 11:39:22.172 28610-28610/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:39:22.173 28610-28610/im.weiyuan.com.viewutils D/123456: MyView onTouchEvent is called0
07-24 11:39:22.174 28610-28610/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called0
07-24 11:39:22.185 28610-28610/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:39:22.185 28610-28610/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called2
07-24 11:39:22.220 28610-28610/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:39:22.220 28610-28610/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called2
07-24 11:39:22.228 28610-28610/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:39:22.228 28610-28610/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called2
07-24 11:39:22.229 28610-28610/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called1
07-24 11:39:22.229 28610-28610/im.weiyuan.com.viewutils D/123456: activity onTouchEvent is called1
首先是activity去分发事件,将事件分发给图片,图片没有孩子,不会再继续分发事件,这个时候取调用图片的回调方法TouchListen,然后调用MyView onTouchEvent去消费事件,
因为MyView onTouchEvent函数的返回值不是true,没有消费给事件,如果返回值是true,事件就被消费了,事件必须要有消费者,所以只能又把事件让给activity去处理,所以接下来调用了activity的: activity onTouchEvent is called0
后面调用了activity的 2 就是move事件,这里默认事件不再分发给图片处理了,为啥了,因为分发给图片的down 事件都没有消费,所以move事件就不会在分发给图片处理了
我们来验证下,我们把代码返回值设置成true
package im.weiyuan.com.viewutils; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; /** * Created by wei.yuan on 2017/7/24. */ public class MyView extends ImageView { public MyView(Context context) { super(context); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public MyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.d("123456","MyView dispatchTouchEvent is called"+event.getAction()); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d("123456","MyView onTouchEvent is called"+event.getAction()); return true; } }
07-24 11:47:41.893 2667-2667/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called0
07-24 11:47:41.894 2667-2667/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called0
07-24 11:47:41.894 2667-2667/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:47:41.895 2667-2667/im.weiyuan.com.viewutils D/123456: MyView onTouchEvent is called0
07-24 11:47:41.919 2667-2667/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:47:41.919 2667-2667/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called2
07-24 11:47:41.919 2667-2667/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:47:41.919 2667-2667/im.weiyuan.com.viewutils D/123456: MyView onTouchEvent is called2
07-24 11:47:41.925 2667-2667/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called1
07-24 11:47:41.926 2667-2667/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called1
07-24 11:47:41.926 2667-2667/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:47:41.926 2667-2667/im.weiyuan.com.viewutils D/123456: MyView onTouchEvent is called1
activity将时间分发给图片去处理,不管是down事件还是move事件,消费者都是图片
接下来做下面的事情,将图片的touch回调事件的返回值设置成true
package im.weiyuan.com.viewutils; import android.content.Intent; import android.os.PersistableBundle; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private MyView view; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); view = (MyView) findViewById(R.id.view_main); /** * 设置touch监听事件 * */ view.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.d("123456","MyView setOnTouchListener is called "); return true; } }); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.d("123456","activity dispatchTouchEvent is called" +ev.getAction()); return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d("123456","activity onTouchEvent is called"+event.getAction()); return super.onTouchEvent(event); } }
package im.weiyuan.com.viewutils; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; /** * Created by wei.yuan on 2017/7/24. */ public class MyView extends ImageView { public MyView(Context context) { super(context); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public MyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.d("123456","MyView dispatchTouchEvent is called"+event.getAction()); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d("123456","MyView onTouchEvent is called"+event.getAction()); return true; } }
我们来看下日志的打印:
07-24 11:51:23.555 9263-9263/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called0
07-24 11:51:23.556 9263-9263/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called0
07-24 11:51:23.556 9263-9263/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:51:23.591 9263-9263/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:51:23.591 9263-9263/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called2
07-24 11:51:23.591 9263-9263/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:51:23.592 9263-9263/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called1
07-24 11:51:23.592 9263-9263/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called1
07-24 11:51:23.592 9263-9263/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
我们来分析下,这个时候activity将事件分发给图片,因为图片的回调函数返回值是true,默认是回调函数对事件进行了消费了,所以这个时候就不会在调用图片的onTouchEvent消费事件了,事件的消费都有回调函数来进行处理了,一个事件只能被消费一次,
如果事件不被视图消费,最终由activity消费
我们来在做下面的修改
package im.weiyuan.com.viewutils; import android.content.Intent; import android.os.PersistableBundle; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private MyView view; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); view = (MyView) findViewById(R.id.view_main); /** * 设置touch监听事件 * */ view.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { Log.d("123456","MyView setOnTouchListener is called "); if(event.getAction() == MotionEvent.ACTION_DOWN){ return true; } return false; } }); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { Log.d("123456","activity dispatchTouchEvent is called" +ev.getAction()); return super.dispatchTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d("123456","activity onTouchEvent is called"+event.getAction()); return super.onTouchEvent(event); } }
package im.weiyuan.com.viewutils; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.ImageView; /** * Created by wei.yuan on 2017/7/24. */ public class MyView extends ImageView { public MyView(Context context) { super(context); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public MyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @Override public boolean dispatchTouchEvent(MotionEvent event) { Log.d("123456","MyView dispatchTouchEvent is called"+event.getAction()); return super.dispatchTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { Log.d("123456","MyView onTouchEvent is called"+event.getAction()); return true; } }
我们来看看日志的打印:
07-24 11:58:28.653 16280-16280/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called0
07-24 11:58:28.654 16280-16280/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called0
07-24 11:58:28.654 16280-16280/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:58:28.657 16280-16280/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:58:28.657 16280-16280/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called2
07-24 11:58:28.658 16280-16280/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:58:28.658 16280-16280/im.weiyuan.com.viewutils D/123456: MyView onTouchEvent is called2
07-24 11:58:28.674 16280-16280/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:58:28.674 16280-16280/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called2
07-24 11:58:28.674 16280-16280/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:58:28.674 16280-16280/im.weiyuan.com.viewutils D/123456: MyView onTouchEvent is called2
07-24 11:58:28.690 16280-16280/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:58:28.691 16280-16280/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called2
07-24 11:58:28.691 16280-16280/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:58:28.691 16280-16280/im.weiyuan.com.viewutils D/123456: MyView onTouchEvent is called2
07-24 11:58:28.757 16280-16280/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called2
07-24 11:58:28.758 16280-16280/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called2
07-24 11:58:28.758 16280-16280/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:58:28.758 16280-16280/im.weiyuan.com.viewutils D/123456: MyView onTouchEvent is called2
07-24 11:58:28.758 16280-16280/im.weiyuan.com.viewutils D/123456: activity dispatchTouchEvent is called1
07-24 11:58:28.758 16280-16280/im.weiyuan.com.viewutils D/123456: MyView dispatchTouchEvent is called1
07-24 11:58:28.758 16280-16280/im.weiyuan.com.viewutils D/123456: MyView setOnTouchListener is called
07-24 11:58:28.758 16280-16280/im.weiyuan.com.viewutils D/123456: MyView onTouchEvent is called1
以上是关于android 事件分发机制的主要内容,如果未能解决你的问题,请参考以下文章