学习Android的第二十六天

目录

[Android Gesture 手势](#Android Gesture 手势)

[Android 中手势交互的执行顺序](#Android 中手势交互的执行顺序)

GestureListener

SimpleOnGestureListener

范例

参考文档

[Android Gesture 手势添加与识别](#Android Gesture 手势添加与识别)

使用GestureLibraries

范例

参考文档


Android Gesture 手势

手势操作在现代移动应用中扮演了非常重要的角色,它不仅提高了用户体验,还增加了应用的互动性和直观性。在Android开发中,实现手势识别是一项基本而重要的技能。Android系统为开发者提供了强大的手势识别功能,让开发者可以轻松地在自己的应用中实现各种手势操作。

Android 中手势交互的执行顺序

1、触摸屏幕事件发生:当用户用手指触摸屏幕时,系统生成一个MotionEvent事件。

2、MotionEvent传递给OnTouchListener:如果你为某个View设置了OnTouchListener,那么这个View上的触摸事件首先会被OnTouchListener的onTouch()方法捕获。

java 复制代码
view.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        // 处理触摸事件
        return false;
    }
});

3、MotionEvent转发给GestureDetector:在OnTouchListener的onTouch()方法内,可以将MotionEvent对象传递给GestureDetector处理。

java 复制代码
@Override
public boolean onTouch(View v, MotionEvent event) {
    return gestureDetector.onTouchEvent(event);
}

4、GestureDetector处理并回调OnGestureListener:GestureDetector内部根据MotionEvent事件的序列来识别具体的手势动作,并根据识别结果调用OnGestureListener接口中相应的方法。

java 复制代码
GestureDetector gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
    @Override
    public boolean onDown(MotionEvent e) {
        // 当用户按下时触发
        return true;
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        // 用户执行fling操作时触发
        return true;
    }

    // 其他手势回调如onScroll, onLongPress等
});

关键组件说明

  • MotionEvent:这个类封装了触摸屏幕时的动作事件(如触摸、移动、松开等),以及触摸点的坐标和其他信息。
  • GestureDetector:这个类用于识别一系列的手势动作。它可以处理由MotionEvent输入的手势,并根据这些手势调用OnGestureListener接口中的方法。
  • OnGestureListener:这是一个监听手势交互的接口,提供了多个抽象方法以响应不同的手势事件,如单击、滑动、长按等。开发者通过实现这些方法来定义特定手势的响应行为。

通过这种机制,Android应用可以灵活地响应和处理用户的手势操作,从而提供丰富的交互体验。需要注意的是,在OnTouchListener的onTouch()方法中返回true表示该触摸事件已被消费,不会再向后传递;返回false则表示事件未被消费,还可以继续传递给其他监听器或处理方法。

GestureListener

GestureListener是Android中处理手势操作的重要接口,它提供了一系列回调方法来响应用户的不同手势动作。这些手势包括但不限于按下、抛掷、长按、滚动、按住和抬起等。下面将详细解释每个回调方法及其用途:

  1. onDown(MotionEvent e)
  • 说明:当用户的手指刚刚接触到触摸屏时触发。这是最基本的手势识别方法,几乎所有的手势识别都是从onDown()开始的。
  • 用途:可以用来初始化某些操作,比如高亮显示被触摸的元素。
  1. onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
  • 说明:当用户在触摸屏上迅速移动手指并松开时触发。e1和e2分别是手指按下和抬起时的MotionEvent对象,velocityX和velocityY表示手指离开屏幕时的速度。
  • 用途:常用于实现翻页效果或者删除条目时的快速滑动。
  1. onLongPress(MotionEvent e)
  • 说明:当用户的手指按在屏幕上持续一段时间,并且没有松开时触发。
  • 用途:用于显示上下文菜单、进入拖拽模式等操作。
  1. onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
  • 说明:当用户的手指在屏幕上滑动时触发。e1是手指按下时的MotionEvent对象,e2是当前移动事件的MotionEvent对象,distanceX和distanceY表示从上一个事件到这个事件的滑动距离。
  • 用途:用于实现滚动列表、图片查看器中的图片滑动等。
  1. onShowPress(MotionEvent e)
  • 说明:当用户的手指按在触摸屏上,且还未移动或松开时触发。它的时间范围在按下起效,在长按之前。
  • 用途:可以用来给用户一个视觉反馈,表明他们的按压已经被识别,但还未触发长按。
  1. onSingleTapUp(MotionEvent e)
  • 说明:当用户的手指离开触摸屏的那一刹那触发。
  • 用途:用于处理轻触屏幕的点击操作,比如打开一个新的界面或触发按钮等。

SimpleOnGestureListener

如果我们只想要在应用中处理一种或少数几种手势,使用GestureDetector.SimpleOnGestureListener会是一个更加便捷和高效的选择。SimpleOnGestureListener是一个实现了GestureDetector.OnGestureListener和GestureDetector.OnDoubleTapListener接口的类,为所有的手势提供了空实现。这意味着我们可以只覆盖(重写)你感兴趣的那些手势方法,而不是所有的方法。

比如,如果你只对滑动手势(onScroll)感兴趣,你可以创建一个GestureDetector对象,并传入一个匿名内部类,该类继承自SimpleOnGestureListener,然后只重写onScroll方法。

范例

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tv_gesture"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="请在此区域内尝试不同的手势"
        android:textSize="24sp"/>

</RelativeLayout>
java 复制代码
package com.example.myapplication3;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private GestureDetector gestureDetector;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        gestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onDown(MotionEvent e) {
                showToast("按下");
                return true;
            }

            @Override
            public void onLongPress(MotionEvent e) {
                showToast("长按");
            }

            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                showToast("抛掷");
                return true;
            }

            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                showToast("滚动");
                return true;
            }

            @Override
            public void onShowPress(MotionEvent e) {
                showToast("按住");
            }

            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                showToast("单击抬起");
                return true;
            }
        });
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        gestureDetector.onTouchEvent(event);
        return super.onTouchEvent(event);
    }

    private void showToast(String message) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
    }
}

参考文档

  1. Android GestureDetector

Android Gesture 手势添加与识别

在Android应用开发中,GestureLibrary和GestureOverlayView是实现高级手势识别和处理的重要工具。通过使用这些工具,开发者可以创建、存储、识别自定义手势,并在应用中实现丰富的交互体验。

使用GestureLibraries

加载手势库:

首先,需要从某个位置加载一个手势库。Android提供了几种加载手势库的方法:

  • fromFile(String path) 或 fromFile(File path):从文件系统中的指定路径加载手势库。
  • fromPrivateFile(Context context, String name):从应用的私有文件目录加载手势库。
  • fromRawResource(Context context, int resourceId):从应用的资源文件中加载手势库。

示例

java 复制代码
GestureLibrary gestureLib = GestureLibraries.fromRawResource(context, R.raw.gestures);
if (!gestureLib.load()) {
    // 手势库加载失败处理
}

使用手势库:

加载手势库后,可以使用GestureLibrary对象提供的方法来管理和识别手势。

  • 添加手势:addGesture(String entryName, Gesture gesture)
  • 获取所有手势名称:getGestureEntries()
  • 根据名称获取手势:getGestures(String entryName)
  • 识别手势:recognize(Gesture gesture)
  • 删除手势或手势集:removeEntry(String entryName) 和 removeGesture(String entryName, Gesture gesture)
  • 保存手势库:save()

使用GestureOverlayView

GestureOverlayView是一个透明的覆盖层,允许用户在其上绘制手势。它提供了三种监听器接口来响应手势事件:

  • OnGestureListener:在手势绘制过程中提供回调。
  • OnGesturePerformedListener:当用户完成手势绘制时触发。
  • OnGesturingListener:提供关于手势开始和结束的回调。

最常用的是OnGesturePerformedListener,它用于在用户完成手势绘制时进行响应。

范例

XML 复制代码
<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="请在下方屏幕中绘制手势~"
        android:textSize="20sp"/>

    <!-- gestureStrokeType 控制手势是否需要一笔完成,multiple 表示允许多笔 -->
    <android.gesture.GestureOverlayView
        android:id="@+id/gesture"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gestureStrokeType="multiple" />

</LinearLayout>
XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<!--    dialog_save.xml-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="8dp"
            android:text="输入手势名称"/>
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/gesture_name"/>
    </LinearLayout>

    <ImageView
        android:id="@+id/gesture_show"
        android:layout_width="128dp"
        android:layout_height="128dp"
        android:layout_marginTop="10dp"/>

</LinearLayout>
java 复制代码
package com.example.myapplication3;

import android.gesture.Gesture;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.gesture.GestureLibraries;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import java.io.File;

public class MainActivity extends AppCompatActivity {

    private GestureOverlayView gestureOverlayView;
    private GestureLibrary gestureLibrary;

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

        gestureOverlayView = findViewById(R.id.gesture);
        gestureOverlayView.setGestureColor(Color.GREEN);
        gestureOverlayView.setGestureStrokeWidth(5);
        gestureOverlayView.addOnGesturePerformedListener(this::onGesturePerformed);

        // 初始化手势库
        String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/myGestures";
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }
        gestureLibrary = GestureLibraries.fromFile(file);
    }

    private void onGesturePerformed(GestureOverlayView overlay, final Gesture gesture) {
        View saveDialog = getLayoutInflater().inflate(R.layout.dialog_save, null, false);
        ImageView imgShow = saveDialog.findViewById(R.id.gesture_show);
        final EditText editName = saveDialog.findViewById(R.id.gesture_name);
        Bitmap bitmap = gesture.toBitmap(128, 128, 10, 0xffff0000);
        imgShow.setImageBitmap(bitmap);

        new AlertDialog.Builder(this)
                .setView(saveDialog)
                .setPositiveButton("保存", (dialogInterface, i) -> saveGesture(gesture, editName.getText().toString()))
                .setNegativeButton("取消", null)
                .show();
    }

    private void saveGesture(Gesture gesture, String name) {
        if (!gestureLibrary.load()) {
            Toast.makeText(this, "手势库加载失败!", Toast.LENGTH_SHORT).show();
            return;
        }

        gestureLibrary.addGesture(name, gesture);
        boolean isSaved = gestureLibrary.save();
        if (isSaved) {
            Toast.makeText(this, "手势保存成功!", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "手势保存失败!", Toast.LENGTH_SHORT).show();
        }
    }
}

然后在 AndroidManifest.xml 文件中加入读 SD 卡的权限

XML 复制代码
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

参考文档

  1. 官方 API 文档: GestureDetector
相关推荐
沪漂阿龙19 分钟前
深度剖析神经网络学习:从损失函数到SGD,手写数字识别完整实战
人工智能·神经网络·学习
迷路爸爸18023 分钟前
Docker 入门学习笔记 06:用一个可复现的 Python 项目真正理解 Dockerfile
笔记·学习·docker
ghie909029 分钟前
基于学习的模型预测控制(LBMPC)MATLAB实现指南
开发语言·学习·matlab
Engineer邓祥浩29 分钟前
JVM学习笔记(6) 第二部分 自动内存管理 第5章节 调优案例分析与实战
jvm·笔记·学习
倒酒小生42 分钟前
4月7日算法学习小结
linux·服务器·学习
xinzheng新政1 小时前
Javascript·深入学习基础知识2
开发语言·javascript·学习
代码s贝多芬的音符1 小时前
android mlkit 实现仰卧起坐和俯卧撑识别
android
世人万千丶1 小时前
开源鸿蒙跨平台Flutter开发:儿童数理认知与神经塑性演化引擎_突触发生与工作记忆测绘架构
学习·flutter·华为·开源·harmonyos
ZhiqianXia1 小时前
PyTorch 学习笔记(10) : PyTorch torch.library
pytorch·笔记·学习
小陈phd1 小时前
多模态大模型学习笔记(三十一)—— 基于CCT(Compact Convolutional Transformers)实现中文车牌数据集微调
笔记·学习