章节索引 :

触摸事件分发

用户在使用 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. 触摸事件示例

在实际开发中,大多数时候我们需要监听的是DOWNMOVE以及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">

    <TextView
        android: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" />

    <TextView
        android: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" />

    <TextView
        android: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" />

    <TextView
        android: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" />

    <TextView
        android: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" />

    <TextView
        android: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;

    @Override
    protected 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() {
            @Override
            public 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()事件后最常用的一个事件,也是绝大多数事件分发的基础事件,因为各种交互事件都是从触摸开始的,所以大家即使用的不多也一定要掌握使用方法及其中的基本原理。

环境搭建,开发相关
Android 系统背景及结构概述 Android 开发环境搭建 Genymotion 的安装与使用 Android 工程解析及使用 Android 程序签名打包
常用 UI 布局
Android 的 UI 根基 View与View Android 线性布局 LinearLayout Android相对布局RelativeLayout Android 表格布局 TableLayout Android 网格布局 GridLayout Android 帧布局 FrameLayout Android绝对布局AbsoluteLayout
基础控件
Android 文本框 TextView Android 文本输入框 EditText 按钮 Button/ImageButton 选择框 RadioButton/Check 开关控件ToggleButton/Switch Android 图片控件 ImageView Android 进度条 ProgressBar Android 拖动条 SeekBar Android 评分条 RatingBar Android 滚动条 ScrollView 轮播滚动视图 ViewFlipper
Adapter 相关控件
Android 适配器 Adapter Android 列表控件 ListView Android 网格视图 GridView Android 下拉选择框 Spinner 自动补全文本框 AutoCompleteText 折叠列表 ExpandableListView
提示类控件
吐司提示:Toast 的使用方法 状态栏通知:Notification 对话框:AlertDialog 悬浮窗:PopupWindow
菜单类控件
菜单:Menu
其他控件
视频页面:ViewPager 侧滑菜单:DrawerLayout
事件处理机制
基于监听的事件处理机制 Handler 消息传递机制 触摸事件分发处理 AsyncTask:异步任务 Android 手势处理
Android 四大组件
活动:Activity 服务:Service 广播接收器:Broadcast Receiver 内容提供者 - Content Provider
数据存储
文件存储 SharedPreferences 存储 数据库:SQLite 的使用
网络编程
HTTP 使用详解 xml 数据解析 JSON 数据解析 网页视图:WebView Socket 网络接口
绘图与动画
图片资源:Drawable 位图:Bitmap
多媒体开发
媒体播放器:MediaPlayer 相机:Camera 音频录制:MediaRecorder
并发编程
多线程