目录
手势操作在现代移动应用中扮演了非常重要的角色,它不仅提高了用户体验,还增加了应用的互动性和直观性。在Android开发中,实现手势识别是一项基本而重要的技能。Android系统为开发者提供了强大的手势识别功能,让开发者可以轻松地在自己的应用中实现各种手势操作。
1、触摸屏幕事件发生:当用户用手指触摸屏幕时,系统生成一个MotionEvent事件。
2、MotionEvent传递给OnTouchListener:如果你为某个View设置了OnTouchListener,那么这个View上的触摸事件首先会被OnTouchListener的onTouch()方法捕获。
- view.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- // 处理触摸事件
- return false;
- }
- });
3、MotionEvent转发给GestureDetector:在OnTouchListener的onTouch()方法内,可以将MotionEvent对象传递给GestureDetector处理。
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- return gestureDetector.onTouchEvent(event);
- }
4、GestureDetector处理并回调OnGestureListener:GestureDetector内部根据MotionEvent事件的序列来识别具体的手势动作,并根据识别结果调用OnGestureListener接口中相应的方法。
- 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等
- });
关键组件说明
通过这种机制,Android应用可以灵活地响应和处理用户的手势操作,从而提供丰富的交互体验。需要注意的是,在OnTouchListener的onTouch()方法中返回true表示该触摸事件已被消费,不会再向后传递;返回false则表示事件未被消费,还可以继续传递给其他监听器或处理方法。
GestureListener是Android中处理手势操作的重要接口,它提供了一系列回调方法来响应用户的不同手势动作。这些手势包括但不限于按下、抛掷、长按、滚动、按住和抬起等。下面将详细解释每个回调方法及其用途:
1. onDown(MotionEvent e)
2. onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
3. onLongPress(MotionEvent e)
4. onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
5. onShowPress(MotionEvent e)
6. onSingleTapUp(MotionEvent e)
如果我们只想要在应用中处理一种或少数几种手势,使用GestureDetector.SimpleOnGestureListener会是一个更加便捷和高效的选择。SimpleOnGestureListener是一个实现了GestureDetector.OnGestureListener和GestureDetector.OnDoubleTapListener接口的类,为所有的手势提供了空实现。这意味着我们可以只覆盖(重写)你感兴趣的那些手势方法,而不是所有的方法。
比如,如果你只对滑动手势(onScroll)感兴趣,你可以创建一个GestureDetector对象,并传入一个匿名内部类,该类继承自SimpleOnGestureListener,然后只重写onScroll方法。
- "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>
- 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();
- }
- }
在Android应用开发中,GestureLibrary和GestureOverlayView是实现高级手势识别和处理的重要工具。通过使用这些工具,开发者可以创建、存储、识别自定义手势,并在应用中实现丰富的交互体验。
加载手势库:
首先,需要从某个位置加载一个手势库。Android提供了几种加载手势库的方法:
示例
- GestureLibrary gestureLib = GestureLibraries.fromRawResource(context, R.raw.gestures);
- if (!gestureLib.load()) {
- // 手势库加载失败处理
- }
使用手势库:
加载手势库后,可以使用GestureLibrary对象提供的方法来管理和识别手势。
使用GestureOverlayView
GestureOverlayView是一个透明的覆盖层,允许用户在其上绘制手势。它提供了三种监听器接口来响应手势事件:
最常用的是OnGesturePerformedListener,它用于在用户完成手势绘制时进行响应。
- "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"/>
-
-
- <android.gesture.GestureOverlayView
- android:id="@+id/gesture"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gestureStrokeType="multiple" />
-
- LinearLayout>
- "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: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>
- 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 卡的权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>