最新消息:欢迎访问Android开发中文站!商务联系微信:loading_in

Android的事件机制

新手入门 AndroidChina 1409浏览 0评论

一、理论概述

最基本的操作类型:

  • down 手指按下
  • move 手指在屏幕上移动
  • up 手指从屏幕上离开

触屏操作的顺序:down->move->move->…->up

对屏幕的任一操作,系统都会产生一个MotionEvent对象来对应这个对象。

注:点击和长按可以同时满足,如果只想满足长按,则让长按的监听返回true。点击和长按时可以move。

二、相关API

1、MotionEvent:触发事件

  • int ACTION_DOWN = 0 : 代表down
  • int ACTION_MOVE = 2 : 代表move
  • int ACTION_UP = 1 : 代表up
  • getAction() : 得到事件类型
  • getX() : 得到事件发生的X轴的坐标(相对于当前视图)
  • getRawX() : 得到事件发生的X轴的坐标(相对于屏幕左顶点)
  • getY() : 得到事件发生的Y轴的坐标(相对于当前视图)
  • getRawY() : 得到事件发生的Y轴的坐标(相对于屏幕左顶点)

2、Activity

  • boolean dispatchTouchEvent(MotionEvent event) : 分发事件
  • boolean onTouchEvent(MotionEvent event) : 处理事件的回调(当没有子View消费时才调用该方法)

3、View

  • boolean dispatchTouchEvent(MotionEvent event) : 分发事件(没有子view,用来决定是使用onTouchEvent还是setOnTouchListener)
  • boolean onTouchEvent(MotionEvent event) : 处理事件的回调方法
  • void setOnTouchListener(OnTouchListener listener) : 设置事件监听器
  • void setOnClickListener(OnClickListener l)
  • void setOnLongClickListener(OnClickListener l)
  • void setOnCreateContextMenuListener(OnCreateContextMenuListener l) 用于创建菜单监听

4、ViewGroup

  • boolean dispatchTouchEvent(MotionEvent event) : 分发事件
  • boolean onInterceptTouchEvent(MotionEvent event) : 拦截事件的回调方法

注:这里引入两个概念:处理和消费
只要调用了方法就叫做处理了;
只有返回了true才叫消费了;

事件对象被系统创建后,首先会调用对应Activity的dispatchTouchEvent()进行分发;

  • down在分发给视图对象的过程中要确定消费者(onTouchEvent()返回true),如果都返回false,那事件的消费者只能是activity了。
  • 后面的move和up都将分发给消费者(可能是视图对象,也可能是消费者)
  • 当前事件的消费者只是决定了下一个事件优先交给他处理
  • 每个事件都需要有一个消费者

例子:

MotionEventActivity.java

package com.cwenhui.motionevent;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import com.cwenhui.test.R;

/**
 * Created by cwenhui on 2016.02.23
 */
public class MotionEventActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_motionevent);

        findViewById(R.id.myImageview).setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e("MotionEventActivity", "setOnTouchListener");
                return false;
            }
        });
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        Log.e("MotionEventActivity", "dispatchTouchEvent--"+ev.getAction());
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("MotionEventActivity", "onTouchEvent--"+event.getAction());
        return super.onTouchEvent(event);
    }
}

layout_motionevent.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:gravity="center"
              android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="motionEvent"/>

    <com.cwenhui.motionevent.MyImageView
        android:id="@+id/myImageview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/test"/>

</LinearLayout>

MyImageview.java

package com.cwenhui.motionevent;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ImageView;

/**
 * Created by cwenhui on 2016.02.23
 */
public class MyImageView extends ImageView {
    public MyImageView(Context context) {
        super(context);
    }

    public MyImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        Log.e("MyImageView", "MyImageView");
    }

    public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        Log.e("MyImageView", "dispatchTouchEvent--"+event.getAction());
        return super.dispatchTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("MyImageView", "onTouchEvent--"+event.getAction());
        return super.onTouchEvent(event)/*true*/;
    }
}

运行分析:
运行结果

如果点击图片并滑动,则

09-20 03:20:37.674 25085-25085/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--0
09-20 03:20:37.674 25085-25085/com.cwenhui.test E/MyImageView: dispatchTouchEvent--0
09-20 03:20:37.674 25085-25085/com.cwenhui.test E/MotionEventActivity: setOnTouchListener
09-20 03:20:37.674 25085-25085/com.cwenhui.test E/MyImageView: onTouchEvent--0
09-20 03:20:37.674 25085-25085/com.cwenhui.test E/MotionEventActivity: onTouchEvent--0
09-20 03:20:37.708 25085-25085/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 03:20:37.708 25085-25085/com.cwenhui.test E/MotionEventActivity: onTouchEvent--2
09-20 03:20:37.724 25085-25085/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 03:20:37.724 25085-25085/com.cwenhui.test E/MotionEventActivity: onTouchEvent--2
09-20 03:20:37.741 25085-25085/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 03:20:37.741 25085-25085/com.cwenhui.test E/MotionEventActivity: onTouchEvent--2
09-20 03:20:37.758 25085-25085/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 03:20:37.758 25085-25085/com.cwenhui.test E/MotionEventActivity: onTouchEvent--2
09-20 03:20:37.774 25085-25085/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 03:20:37.774 25085-25085/com.cwenhui.test E/MotionEventActivity: onTouchEvent--2
09-20 03:20:37.802 25085-25085/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--1
09-20 03:20:37.802 25085-25085/com.cwenhui.test E/MotionEventActivity: onTouchEvent--1

如果将MyImageview.java中的onTouchEvent(MotionEvent event)返回值改为true,则

09-20 03:22:16.122 2077-2077/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--0
09-20 03:22:16.122 2077-2077/com.cwenhui.test E/MyImageView: dispatchTouchEvent--0
09-20 03:22:16.122 2077-2077/com.cwenhui.test E/MotionEventActivity: setOnTouchListener
09-20 03:22:16.122 2077-2077/com.cwenhui.test E/MyImageView: onTouchEvent--0
09-20 03:22:16.174 2077-2077/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 03:22:16.174 2077-2077/com.cwenhui.test E/MyImageView: dispatchTouchEvent--2
09-20 03:22:16.174 2077-2077/com.cwenhui.test E/MotionEventActivity: setOnTouchListener
09-20 03:22:16.174 2077-2077/com.cwenhui.test E/MyImageView: onTouchEvent--2
09-20 03:22:16.191 2077-2077/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 03:22:16.191 2077-2077/com.cwenhui.test E/MyImageView: dispatchTouchEvent--2
09-20 03:22:16.191 2077-2077/com.cwenhui.test E/MotionEventActivity: setOnTouchListener
09-20 03:22:16.191 2077-2077/com.cwenhui.test E/MyImageView: onTouchEvent--2
09-20 03:22:16.208 2077-2077/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 03:22:16.208 2077-2077/com.cwenhui.test E/MyImageView: dispatchTouchEvent--2
09-20 03:22:16.208 2077-2077/com.cwenhui.test E/MotionEventActivity: setOnTouchListener
09-20 03:22:16.208 2077-2077/com.cwenhui.test E/MyImageView: onTouchEvent--2
09-20 03:22:16.224 2077-2077/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 03:22:16.224 2077-2077/com.cwenhui.test E/MyImageView: dispatchTouchEvent--2
09-20 03:22:16.224 2077-2077/com.cwenhui.test E/MotionEventActivity: setOnTouchListener
09-20 03:22:16.224 2077-2077/com.cwenhui.test E/MyImageView: onTouchEvent--2
09-20 03:22:16.279 2077-2077/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--1
09-20 03:22:16.279 2077-2077/com.cwenhui.test E/MyImageView: dispatchTouchEvent--1
09-20 03:22:16.279 2077-2077/com.cwenhui.test E/MotionEventActivity: setOnTouchListener
09-20 03:22:16.279 2077-2077/com.cwenhui.test E/MyImageView: onTouchEvent--1

如果此时MotionEventActivity中的OnTouchListener的onTouch()方法返回true,如下:

findViewById(R.id.myImageview).setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e("MotionEventActivity", "setOnTouchListener--"+event.getAction());
                return true;
            }
        });

运行结果如下:

09-20 15:01:53.068 3767-3767/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--0
09-20 15:01:53.068 3767-3767/com.cwenhui.test E/MyImageView: dispatchTouchEvent--0
09-20 15:01:53.068 3767-3767/com.cwenhui.test E/MotionEventActivity: setOnTouchListener
09-20 15:01:53.105 3767-3767/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 15:01:53.105 3767-3767/com.cwenhui.test E/MyImageView: dispatchTouchEvent--2
09-20 15:01:53.105 3767-3767/com.cwenhui.test E/MotionEventActivity: setOnTouchListener
09-20 15:01:53.122 3767-3767/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 15:01:53.122 3767-3767/com.cwenhui.test E/MyImageView: dispatchTouchEvent--2
09-20 15:01:53.122 3767-3767/com.cwenhui.test E/MotionEventActivity: setOnTouchListener
09-20 15:01:53.138 3767-3767/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 15:01:53.139 3767-3767/com.cwenhui.test E/MyImageView: dispatchTouchEvent--2
09-20 15:01:53.139 3767-3767/com.cwenhui.test E/MotionEventActivity: setOnTouchListener
09-20 15:01:53.155 3767-3767/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 15:01:53.155 3767-3767/com.cwenhui.test E/MyImageView: dispatchTouchEvent--2
09-20 15:01:53.155 3767-3767/com.cwenhui.test E/MotionEventActivity: setOnTouchListener
09-20 15:01:53.172 3767-3767/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 15:01:53.172 3767-3767/com.cwenhui.test E/MyImageView: dispatchTouchEvent--2
09-20 15:01:53.172 3767-3767/com.cwenhui.test E/MotionEventActivity: setOnTouchListener
09-20 15:01:53.189 3767-3767/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 15:01:53.189 3767-3767/com.cwenhui.test E/MyImageView: dispatchTouchEvent--2
09-20 15:01:53.189 3767-3767/com.cwenhui.test E/MotionEventActivity: setOnTouchListener
09-20 15:01:53.237 3767-3767/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 15:01:53.237 3767-3767/com.cwenhui.test E/MyImageView: dispatchTouchEvent--2
09-20 15:01:53.237 3767-3767/com.cwenhui.test E/MotionEventActivity: setOnTouchListener
09-20 15:01:53.237 3767-3767/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--1
09-20 15:01:53.237 3767-3767/com.cwenhui.test E/MyImageView: dispatchTouchEvent--1
09-20 15:01:53.237 3767-3767/com.cwenhui.test E/MotionEventActivity: setOnTouchListener

可见,没有执行MyImageview的onTouchEvent(MotionEvent event)方法了。

如果改成手指按下时返回true,即

findViewById(R.id.myImageview).setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.e("MotionEventActivity", "setOnTouchListener--"+event.getAction());
//                return false;
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    return true;
                }

                return false;
            }
        });

结果为:

09-20 16:30:48.573 16591-16591/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--0
09-20 16:30:48.573 16591-16591/com.cwenhui.test E/MyImageView: dispatchTouchEvent--0
09-20 16:30:48.573 16591-16591/com.cwenhui.test E/MotionEventActivity: setOnTouchListener--0
09-20 16:30:48.605 16591-16591/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 16:30:48.605 16591-16591/com.cwenhui.test E/MyImageView: dispatchTouchEvent--2
09-20 16:30:48.605 16591-16591/com.cwenhui.test E/MotionEventActivity: setOnTouchListener--2
09-20 16:30:48.605 16591-16591/com.cwenhui.test E/MyImageView: onTouchEvent--2
09-20 16:30:48.622 16591-16591/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 16:30:48.622 16591-16591/com.cwenhui.test E/MyImageView: dispatchTouchEvent--2
09-20 16:30:48.622 16591-16591/com.cwenhui.test E/MotionEventActivity: setOnTouchListener--2
09-20 16:30:48.622 16591-16591/com.cwenhui.test E/MyImageView: onTouchEvent--2
09-20 16:30:48.638 16591-16591/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 16:30:48.639 16591-16591/com.cwenhui.test E/MyImageView: dispatchTouchEvent--2
09-20 16:30:48.639 16591-16591/com.cwenhui.test E/MotionEventActivity: setOnTouchListener--2
09-20 16:30:48.639 16591-16591/com.cwenhui.test E/MyImageView: onTouchEvent--2
09-20 16:30:48.655 16591-16591/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 16:30:48.655 16591-16591/com.cwenhui.test E/MyImageView: dispatchTouchEvent--2
09-20 16:30:48.655 16591-16591/com.cwenhui.test E/MotionEventActivity: setOnTouchListener--2
09-20 16:30:48.655 16591-16591/com.cwenhui.test E/MyImageView: onTouchEvent--2
09-20 16:30:48.672 16591-16591/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 16:30:48.672 16591-16591/com.cwenhui.test E/MyImageView: dispatchTouchEvent--2
09-20 16:30:48.672 16591-16591/com.cwenhui.test E/MotionEventActivity: setOnTouchListener--2
09-20 16:30:48.672 16591-16591/com.cwenhui.test E/MyImageView: onTouchEvent--2
09-20 16:30:48.689 16591-16591/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--2
09-20 16:30:48.689 16591-16591/com.cwenhui.test E/MyImageView: dispatchTouchEvent--2
09-20 16:30:48.689 16591-16591/com.cwenhui.test E/MotionEventActivity: setOnTouchListener--2
09-20 16:30:48.689 16591-16591/com.cwenhui.test E/MyImageView: onTouchEvent--2
09-20 16:30:48.717 16591-16591/com.cwenhui.test E/MotionEventActivity: dispatchTouchEvent--1
09-20 16:30:48.717 16591-16591/com.cwenhui.test E/MyImageView: dispatchTouchEvent--1
09-20 16:30:48.718 16591-16591/com.cwenhui.test E/MotionEventActivity: setOnTouchListener--1
09-20 16:30:48.718 16591-16591/com.cwenhui.test E/MyImageView: onTouchEvent--1

可见down的时候,事件对象是给OnTouchListener消费了;

move和up时,事件对象给OnTouch消费了。

转载请注明:Android开发中文站 » Android的事件机制

您必须 登录 才能发表评论!