学习Android的第二十六天

目录

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();}
}

参考文档

  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):从应用的资源文件中加载手势库。

示例

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"/>

参考文档

  1. 官方 API 文档: GestureDetector

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/732090.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【动态规划入门】不同的子序列

每日一道算法题之不同的子序列 一、题目二、思路三、C代码 一、题目 题目来源&#xff1a;LeetCode【难度&#xff1a;困难】 给你两个字符串 s 和 t &#xff0c;统计并返回在 s 的 子序列 中 t 出现的个数&#xff0c;结果需要对 109 7 取模。 示例如下&#xff1a; 输入&…

数据结构(二)——线性表(单链表)

2.3线性表的链式表示 顺序表的优缺点&#xff1a; 优点&#xff1a;可随机存储&#xff0c;存储密度高 缺点&#xff1a;要求大片连续空间&#xff0c;且改变容量不方便 2.3.1 单链表的基本概念 单链表&#xff1a;用链式存储实现了线性结构。一个结点存储一个数据元素&…

【IEEE列表会议】IEEE第三届信息与通信工程国际会议国际会议(JCICE 2024)

会议简介 Brief Introduction 2024年第三届信息与通信工程国际会议国际会议 (JCICE 2024) 会议时间&#xff1a;2024年5月10日-12日 召开地点&#xff1a;中国福州 大会官网&#xff1a;JCICE 2024-2024 International Joint Conference on Information and Communication Engi…

高电平复位电路工作原理详解

单片机复位电路的作用是&#xff1a;使单片机恢复到起始状态&#xff0c;让单片机的程序从头开始执行&#xff0c;运行时钟处于稳定状态、各种寄存器、端口处于初始化状态等等。目的是让单片机能够稳定、正确的从头开始执行程序。一共分为&#xff1a;高电平复位&#xff0c;低…

程序员失业,被迫开启 PlanB——成为自由职业/独立开发者的第 0 天

程序员失业&#xff0c;被迫开启 PlanB——成为自由职业/独立开发者的第 0 天 今天在逛V2EX的时候看到的一个帖子&#xff0c;程序员中年被裁&#xff0c;被迫开启独立开发这条路。 原贴如下&#xff1a; lastday, 失业啦 公司年前通知我合同到期不续签&#xff0c;今天是我…

docker学习进阶

一、dockerfile解析 官方文档&#xff1a; Dockerfile reference | Docker Docs 1.1、dockfile是什么&#xff1f; dockerfile是用来构建docker镜像的文本文件&#xff0c;由一条条构建镜像所需的指令和参数构成的脚本。 之前我们介绍过通过具体容器反射构建镜像(docker comm…

JavaWeb - 3 - JavaScript(JS)

JavaScript(JS)官方参考文档&#xff1a;JavaScript 教程 JavaScript&#xff08;简称&#xff1a;JS&#xff09;是一门跨平台、面向对象的脚本语言&#xff0c;是用来控制网页行为的&#xff0c;它能使网页可交互&#xff08;脚本语言就不需要编译&#xff0c;直接通过浏览器…

Luajit 2023移动版本编译 v2.1.ROLLING

文章顶部有编好的 2.1.ROLLING 2023/08/21版本源码 Android 64 和 iOS 64 luajit 目前最新的源码tag版本为 v2.1.ROLLING on Aug 21, 2023应该是修正了很多bug, 我是出现下面问题才编的. cocos2dx-lua 游戏 黑屏 并报错: [LUA ERROR] bad light userdata pointer 编…

【校园导航小程序】2.0版本 静态/云开发项目 升级日志

演示视频 【校园导航小程序】2.0版本 静态/云开发项目 演示 首页 重做了首页&#xff0c;界面更加高效和美观 校园指南页 新增了 “校园指南” 功能&#xff0c;可以搜索和浏览校园生活指南 地图页 ①弃用路线规划插件&#xff0c;改用SDK开发包。可以无阻通过审核并发布…

IOS面试题object-c 11-20

11、解释self [super init]方法&#xff1f; 容错处理, 当父类初始化失败,会返回一个nil, 表示初始化失败。 由于继承的关系, 子类是需要拥有父类的实例和行为, 因此, 我们必须先初始化父类,然后再初始化子类 12、简述使用block有什么优点&#xff1f;代码紧凑&#xff0c;传值…

seq2seq翻译实战-Pytorch复现

&#x1f368; 本文为[&#x1f517;365天深度学习训练营学习记录博客 &#x1f366; 参考文章&#xff1a;365天深度学习训练营 &#x1f356; 原作者&#xff1a;[K同学啊 | 接辅导、项目定制]\n&#x1f680; 文章来源&#xff1a;[K同学的学习圈子](https://www.yuque.com/…

前端使用Ant Design中的Modal框实现长按顶部拖动弹框需求

需求&#xff1a;需要Ant Design中的一个Modal弹框&#xff0c;并且可以让用户按住顶部实现拖动操作 实现&#xff1a;在Ant Design的Modal框的基础上&#xff0c;在title中添加一个onMouseDown去记录拖拽的坐标&#xff0c;然后将其赋值给Modal的style属性 代码部分&#xff…

Django中执行update更新时auto_now问题

一、问题说明 在我们给模型的时间字段updated_at字段添加auto_nowTrue之后&#xff0c;原则上来说在更新数据是会自动修改更新时间。 但是当我们使用在代码中使用ORM中的filter(xxxxxx).update(xxxxxx)时发现&#xff0c;更新时间字段并没有完成更新。 而如果使用obj.save()…

【JavaEE进阶】 @Transactional详解

文章目录 &#x1f343;前言&#x1f332;rollbackFor&#xff08;异常回滚属性&#xff09;&#x1f384;事务隔离级别&#x1f6a9;MySQL事务隔离级别&#x1f6a9;Spring事务隔离级别 &#x1f38b;Spring事务传播机制&#x1f6a9;什么是事务传播机制&#x1f6a9;事务有哪…

Android 11 系统开发增加低电量弹窗提示 手机 平板 车载 TV 投影 通用

1、PowerUI是系统中控制电量提示的模块&#xff0c;低电量提醒、低电量关机提醒、高温关机提醒、省电模式都在其中实现 SystemUIService 中启动PowerUI public class SystemUIService extends Service {Overridepublic void onCreate() {super.onCreate();((SystemUIApplicat…

【SpringMVC】RESTFul风格设计和实战 第三期

文章目录 概述一、 RESTFul风格简介二、 RESTFul风格特点三、 RESTFul风格设计规范3.1 HTTP协议请求方式要求3.2 URL路径风格要求 实战一、需求分析二、RESTFul风格接口设计三、后台接口实现总结模糊查询 有范围 返回多数据用户 添加 与 更新 请求参数接收数据显示用户详情/删除…

进腾讯工作一个月,我想辞职了......

前几天&#xff0c;我在网上看到一个微博。 一个应届的校招生&#xff0c;目前入职腾讯&#xff0c;工作了一个月。这一个月给他的感受是大量的写测试用例&#xff0c;自己写测试用例的能力熟练了不少&#xff0c;测试技能倒是没有多大的提高&#xff0c;真正需要技术的工作却…

软考71-上午题-【面向对象技术2-UML】-UML中的图2

一、用例图 上午题&#xff0c;考的少&#xff1b;下午题&#xff0c;考的多。 1-1、用例图的定义 用例图展现了一组用例、参与者以及它们之间的关系。 用例图用于对系统的静态用例图进行建模。 可以用下列两种方式来使用用例图&#xff1a; 1、对系统的语境建模&#xff1b…

【java 分页工具类】分页工具PageBean(149)

分页工具类&#xff1a; package com.itheima3;import java.util.ArrayList; import java.util.List;public class PageBean<T> {private int pageSize; // 每页记录数private int pageNo; // 当前页private int totalPages; // 总页数private int totalRecords; // 总记…

ChatGPT 升级出现「我们未能验证您的支付方式/we are unable to authenticate」怎么办?

ChatGPT 升级出现「我们未能验证您的支付方式/we are unable to authenticate」怎么办&#xff1f; 在订阅 ChatGPT Plus 时&#xff0c;有时候会出现以下报错 &#xff1a; We are unable to authenticate your payment method. 我们未能验证您的支付方式。 出现 unable to a…