用户在使用 Andriod 系统的时候会不断的和我们的 App 进行各种类型的交互(类似点击、滑动等等),“事件”就是一个非常有效的用来收集用户行为的方式。在前面章节有提到过:Android 系统采用一个先进先出(FIFO)队列来维护一个事件 List。在每个事件出列的时候,Android 系统会根据一定的规则对这些事件做分发,我们可以通过接收这些事件来对用户的操作进行相应的处理。
1. 事件处理相关概念
-
Event Listeners Registration:
事件监听器注册。在接收事件之前完成注册,目的是告诉系统当前需要监听某个事件,从而在事件触发的时候系统会回调已注册接口中的方法。 -
Event Listeners:
事件监听器。顾名思义,当某个事件被用户行为触发的时候,系统会回调所有已注册相应事件监听器的回调方法,从而完成事件的分发。 -
Event Handlers:
事件处理。当事件发生时,系统会回调我们注册过的接口,所以可以在回调方法中对事件进行处理
2. 触摸事件类型
一次完整的触摸事件是从手指触摸屏幕一直到离开屏幕,这个过程可能非常短暂,但是对于 Android 系统而言发生了很多状态的切换,常用的主要有以下几种:
- ACTION_DOWN:
手指刚接触到的状态 - ACTION_POINTER_DOWN:
在第一个状态之后其他的点发生了触摸 - ACTION_MOVE:
手指触摸滑动 - ACTION_POINTER_UP:
除了第一个触摸点以外的触摸点离开屏幕 - ACTION_UP:
第一个接触的点离开屏幕 - ACTION_CANCEL:
滑动时移动到无效区域
3. 触摸事件监听方法
3.1 注册触摸监听器
为了能够顺利接收到以上事件,并进行相应处理,我们需要在事件发生之前完成注册,方法如下:
public boolean onTouchEvent(MotionEvent ev){switch(ev.getAction()){case MotionEvent.ACTION_DOWN:{break;}case MotionEvent.ACTION_MOVE:{break;}return true;}
}
3.2 获取触摸坐标
在接收到各个状态的事件之后,我们需要从中获取当前的触摸/滑动坐标,如下:
float x = ev.getX();
float y = ev.getY();
4. 触摸事件示例
在实际开发中,大多数时候我们需要监听的是DOWN
、MOVE
以及UP
三个事件,我们可以在DOWN
事件中获取到触摸的起点,然后在MOVE
过程中获取并不断追踪用户的滑动坐标,最后在UP
事件中获取终点进而结束本次 Touch 事件。
4.1 布局文件
首先编写布局文件,我们需要 4 个 TextView,分别用来显示触摸起点的 X 轴、Y 轴坐标,以及滑动时的 X 轴、Y 轴偏移量,最后创建一个 View 用作触摸事件的接收源。内容非常简单,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:padding="20dp"android:transitionGroup="true"tools:context=".MainActivity"><TextViewandroid:id="@+id/title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentTop="true"android:layout_centerHorizontal="true"android:text="Android 事件处理"android:textSize="35dp" /><TextViewandroid:id="@+id/down_x"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@+id/title"android:layout_alignStart="@+id/title"android:layout_marginTop="30dp"android:hint="点击的X轴坐标"android:textColor="@color/colorPrimary" /><TextViewandroid:id="@+id/down_y"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@+id/down_x"android:layout_alignStart="@+id/down_x"android:layout_marginTop="10dp"android:hint="点击的Y轴坐标"android:textColor="@color/colorPrimary" /><TextViewandroid:id="@+id/move_x"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@+id/down_y"android:layout_alignStart="@+id/down_y"android:layout_marginTop="60dp"android:hint="移动位置的X轴坐标"android:textColor="@color/colorPrimaryDark" /><TextViewandroid:id="@+id/move_y"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@+id/move_x"android:layout_alignStart="@+id/move_x"android:hint="移动位置的Y轴坐标"android:textColor="@color/colorPrimaryDark" /><TextViewandroid:id="@+id/touch"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:text="点我开始滑动"android:textColor="#ff5480ff"android:textSize="35sp" />
</RelativeLayout>
4.2 触摸事件的注册、监听以及处理
在 MainActivity 中我们对 id 为 touch 的 TextView 注册触摸监听器,然后在DOWN
中获取触摸起点,并写在对应的 TextView 中;随后在MOVE
中实时获取滑动偏移量,也在对应的 TextView 中进行实时更新,代码如下:
package com.emercy.myapplication;import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;public class MainActivity extends Activity {float xAxis = 0f;float yAxis = 0f;float downXAxis = 0f;float downYAxis = 0f;TextView downX, downY, moveX, moveY;TextView touch;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);downX = findViewById(R.id.down_x);downY = findViewById(R.id.down_y);moveX = findViewById(R.id.move_x);moveY = findViewById(R.id.move_y);touch = findViewById(R.id.touch);// 1、注册触摸监听器touch.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {final int actionPeformed = event.getAction();// 2、判断当前触摸状态switch (actionPeformed) {case MotionEvent.ACTION_DOWN: {// 3、在不同状态中进行触摸事件处理downXAxis = event.getX();downYAxis = event.getY();downX.setText("按下的位置横坐标:" + downXAxis);downY.setText("按下的位置纵坐标:" + downYAxis);break;}case MotionEvent.ACTION_MOVE: {final float x = event.getX();final float y = event.getY();final float dx = x - downXAxis;final float dy = y - downYAxis;xAxis += dx;yAxis += dy;moveX.setText("移动距离的横坐标:" + xAxis);moveY.setText("移动距离的纵坐标:" + yAxis);break;}}return true;}});}
}
编译运行,效果如下:
触摸左下角的“点我开始滑动”,当前触摸的坐标就会在 TextView 中展示了,然后滑动手指,随着滑动的偏移量的变化,也会在 TextView 中进行同步更新。
5. 小结
本节讲解了触摸事件的分发处理方式,首先介绍了事件处理的几个常用概念及一次触摸事件中切换的几种状态,然后讲述了触摸事件处理的几个重要方法,最后用一个完整例子演示了触摸事件的监听处理。这个是继onClick()
事件后最常用的一个事件,也是绝大多数事件分发的基础事件,因为各种交互事件都是从触摸开始的,所以大家即使用的不多也一定要掌握使用方法及其中的基本原理。