目录
Android Gesture 手势
Android 中手势交互的执行顺序
GestureListener
SimpleOnGestureListener
范例
参考文档
Android Gesture 手势添加与识别
使用GestureLibraries
范例
参考文档
Android Gesture 手势
手势操作在现代移动应用中扮演了非常重要的角色,它不仅提高了用户体验,还增加了应用的互动性和直观性。在Android开发中,实现手势识别是一项基本而重要的技能。Android系统为开发者提供了强大的手势识别功能,让开发者可以轻松地在自己的应用中实现各种手势操作。
Android 中手势交互的执行顺序
1、触摸屏幕事件发生:当用户用手指触摸屏幕时,系统生成一个MotionEvent事件。
2、MotionEvent传递给OnTouchListener:如果你为某个View设置了OnTouchListener,那么这个View上的触摸事件首先会被OnTouchListener的onTouch()方法捕获。
view.setOnTouchListener(new View.OnTouchListener() {@Overridepublic 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() {@Overridepublic boolean onDown(MotionEvent e) {// 当用户按下时触发return true;}@Overridepublic 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()开始的。
- 用途:可以用来初始化某些操作,比如高亮显示被触摸的元素。
2. onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
- 说明:当用户在触摸屏上迅速移动手指并松开时触发。e1和e2分别是手指按下和抬起时的MotionEvent对象,velocityX和velocityY表示手指离开屏幕时的速度。
- 用途:常用于实现翻页效果或者删除条目时的快速滑动。
3. onLongPress(MotionEvent e)
- 说明:当用户的手指按在屏幕上持续一段时间,并且没有松开时触发。
- 用途:用于显示上下文菜单、进入拖拽模式等操作。
4. onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)
- 说明:当用户的手指在屏幕上滑动时触发。e1是手指按下时的MotionEvent对象,e2是当前移动事件的MotionEvent对象,distanceX和distanceY表示从上一个事件到这个事件的滑动距离。
- 用途:用于实现滚动列表、图片查看器中的图片滑动等。
5. onShowPress(MotionEvent e)
- 说明:当用户的手指按在触摸屏上,且还未移动或松开时触发。它的时间范围在按下起效,在长按之前。
- 用途:可以用来给用户一个视觉反馈,表明他们的按压已经被识别,但还未触发长按。
6. onSingleTapUp(MotionEvent e)
- 说明:当用户的手指离开触摸屏的那一刹那触发。
- 用途:用于处理轻触屏幕的点击操作,比如打开一个新的界面或触发按钮等。
SimpleOnGestureListener
如果我们只想要在应用中处理一种或少数几种手势,使用GestureDetector.SimpleOnGestureListener会是一个更加便捷和高效的选择。SimpleOnGestureListener是一个实现了GestureDetector.OnGestureListener和GestureDetector.OnDoubleTapListener接口的类,为所有的手势提供了空实现。这意味着我们可以只覆盖(重写)你感兴趣的那些手势方法,而不是所有的方法。
比如,如果你只对滑动手势(onScroll)感兴趣,你可以创建一个GestureDetector对象,并传入一个匿名内部类,该类继承自SimpleOnGestureListener,然后只重写onScroll方法。
范例
<?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"><TextViewandroid: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;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);gestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {@Overridepublic boolean onDown(MotionEvent e) {showToast("按下");return true;}@Overridepublic void onLongPress(MotionEvent e) {showToast("长按");}@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {showToast("抛掷");return true;}@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {showToast("滚动");return true;}@Overridepublic void onShowPress(MotionEvent e) {showToast("按住");}@Overridepublic boolean onSingleTapUp(MotionEvent e) {showToast("单击抬起");return true;}});}@Overridepublic 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 GestureDetector
Android Gesture 手势添加与识别
在Android应用开发中,GestureLibrary和GestureOverlayView是实现高级手势识别和处理的重要工具。通过使用这些工具,开发者可以创建、存储、识别自定义手势,并在应用中实现丰富的交互体验。
使用GestureLibraries
加载手势库:
首先,需要从某个位置加载一个手势库。Android提供了几种加载手势库的方法:
- fromFile(String path) 或 fromFile(File path):从文件系统中的指定路径加载手势库。
- fromPrivateFile(Context context, String name):从应用的私有文件目录加载手势库。
- fromRawResource(Context context, int resourceId):从应用的资源文件中加载手势库。
示例
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 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"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="请在下方屏幕中绘制手势~"android:textSize="20sp"/><!-- gestureStrokeType 控制手势是否需要一笔完成,multiple 表示允许多笔 --><android.gesture.GestureOverlayViewandroid:id="@+id/gesture"android:layout_width="match_parent"android:layout_height="match_parent"android:gestureStrokeType="multiple" /></LinearLayout>
<?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"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginRight="8dp"android:text="输入手势名称"/><EditTextandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/gesture_name"/></LinearLayout><ImageViewandroid: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;@Overrideprotected 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"/>
参考文档
- 官方 API 文档: GestureDetector