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 事件分发机制的主要内容,如果未能解决你的问题,请参考以下文章

Android ViewGroup事件分发机制

android 事件分发机制

Android View 事件分发机制

Android 事件分发事件分发源码分析 ( ViewGroup 事件传递机制 四 | View 事件传递机制 )

Android事件分发机制五:面试官你坐啊

Android源码分析:View的事件分发机制探析