Android开发中,几乎所有的事件都会和用户进行交互,而最多的交互形式就是手势了。也有很多手势三方的库。比如 android-gesture-detectors 、AndroidPdfViewer(这个库支持pdf文档显示,支持手势),这些三方库都是不错的手势识别。不过今天我们来看看谷歌提供的原生手势识别的相关类和使用方式,以及一些简单的运用。

  • 谷歌官方文档手势识别:https://developer.android.com/reference/android/view/GestureDetector.html

手势呢,大概分为两个大类别,一种是左滑右滑,Google提供了手势检测并提供了相应的监听器,另一种就是画个圆圈,正方形登特殊手势。这种手势需要开发者自己添加手势识别,并提供了相关的API识别用户手势。GestureDetector,提供了简单手势识别和监听回调。GestureDetector谷歌官方文档地址:https://developer.android.com/reference/android/view/GestureDetector.html。GestureDetector主要使用在于手势的的回调监听, GestureDetector.OnGestureListener, GestureDetector.SimpleOnGestureListener,GestureDetector.OnDoubleTapListener。这些监听器才是关键,后面慢慢会讲到。

那么先看看GestureDetector的方法。

  • isLongpressEnabled (),是否允许长点击

  • onTouchEvent(MotionEvent ev) ,拦截事件进行处理。比如在哪个Activity设置手势识别,那么就需要重写该Activity的onTouchEvent。将事件处理转交给GestureDetetor。

  • setIsLongpressEnabled(boolean isLongpressEnabled) ,设置是否允许长点击。

  • setOnDoubleTapListener(GestureDetector.OnDoubleTapListener onDoubleTapListener) ,设置双点击事件回调监听。

GestureDetector的方法,大概也就这些了。关键在于这些手势识别的接口,那么对这些接口的触发以及意义,都挨着使用一次。


GestureDetector.OnGestureListener

这个是常用的接口,作用手势识别的回调。它所有的方法以及意义。

  • OnDown(MotionEvent e):用户按下屏幕就会触发;

  • onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) ,滑屏,用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发 参数解释: e1:第1个ACTION_DOWN MotionEvent e2:最后一个ACTION_MOVE MotionEvent velocityX:X轴上的移动速度,像素/秒 velocityY:Y轴上的移动速度,像素/秒。

  • onLongPress(MotionEvent e) ,长按触摸屏,超过一定时长,就会触发这个事件 触发顺序: onDown->onShowPress->onLongPress。

  • onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) ,在屏幕上拖动事件。无论是用手拖动view,或者是以抛的动作滚动,都会多次触发,这个方法 在ACTION_MOVE动作发生时就会触发 滑屏:手指触动屏幕后,稍微滑动后立即松开 onDown—–》onScroll—-》onScroll—-》onScroll—-》………—–>onFling 拖动 onDown——》onShowPress —》onScroll—-》onScroll——》onFiling 可见,无论是滑屏,还是拖动,影响的只是中间OnScroll触发的数量多少而已,最终都会触发onFling事件!

  • onShowPress(MotionEvent e) ,如果是按下的时间超过瞬间,而且在按下的时候没有松开或者是拖动的,那么onShowPress就会执行。这个时间是底层封装,设定的。开发者在应用层只需应用,不必知晓时间设定以及原理。

  • onSingleTapUp(MotionEvent e) ,顾名思义,一次单独的轻击抬起操作,也就是轻击一下屏幕,立刻抬起来,才会有这个触发,当然,如果除了Down以外还有其它操作,那就不再算是Single操作了,所以也就不会触发这个事件 触发顺序: 点击一下非常快的(不滑动)Touchup: onDown->onSingleTapUp->onSingleTapConfirmed 点击一下稍微慢点的(不滑动)Touchup: onDown->onShowPress->onSingleTapUp->onSingleTapConfirmed。

这些方法就是在用户一些基本手势交互的时候回调。那么写一个简单实例来看看。

public class MainActivity extends AppCompatActivity implements GestureDetector.OnGestureListener {GestureDetector detector;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);detector = new GestureDetector(this,this);detector.setIsLongpressEnabled(true);}//重写Activity的onTouchEvent,将Activity的事件@Overridepublic boolean onTouchEvent(MotionEvent event) {return detector.onTouchEvent(event);}// 用户轻触触摸屏,由1个MotionEvent ACTION_DOWN触发@Overridepublic boolean onDown(MotionEvent motionEvent) {Log.i("tag00", "================================");Log.i("tag00", "onDown");return false;}/** 用户轻触触摸屏,尚未松开或拖动,由一个1个MotionEvent ACTION_DOWN触发* 注意和onDown()的区别,强调的是没有松开或者拖动的状态** 而onDown也是由一个MotionEventACTION_DOWN触发的,但是他没有任何限制,* 也就是说当用户点击的时候,首先MotionEventACTION_DOWN,onDown就会执行,* 如果在按下的瞬间没有松开或者是拖动的时候onShowPress就会执行,如果是按下的时间超过瞬间* (这块我也不太清楚瞬间的时间差是多少,一般情况下都会执行onShowPress),拖动了,就不执行onShowPress。*/@Overridepublic void onShowPress(MotionEvent motionEvent) {Log.i("tag00", "onShowPress");}// 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发// 轻击一下屏幕,立刻抬起来,才会有这个触发// 从名子也可以看出,一次单独的轻击抬起操作,当然,如果除了Down以外还有其它操作,那就不再算是Single操作了,所以这个事件 就不再响应@Overridepublic boolean onSingleTapUp(MotionEvent motionEvent) {Log.i("tag00", "onSingleTapUp");return false;}// 用户按下触摸屏,并拖动,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE触发@Overridepublic boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {Log.i("tag00", "onScroll");return false;}// 用户长按触摸屏,由多个MotionEvent ACTION_DOWN触发@Overridepublic void onLongPress(MotionEvent motionEvent) {Log.i("tag00", "onLongPress");}// 用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发@Overridepublic boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {Log.i("tag00", "onFling");return false;}
}

我的手势依次是:
1、轻触,快速拿起。(1~2S)
2、稍长按,再拿起。(4~6S)
3、长按,再拿起。(8S~)
4、从左至右滑动,再拿起,类似翻页。
5、画圆圈。

I/tag00: ================================
I/tag00: onDown
I/tag00: onSingleTapUp
I/tag00: ================================
I/tag00: onDown
I/tag00: onShowPress
I/tag00: onSingleTapUp
I/tag00: ================================
I/tag00: onDown
I/tag00: onShowPress
I/tag00: onLongPress
I/tag00: ================================
I/tag00: onDown
I/tag00: onScroll
I/tag00: onScroll
I/tag00: onScroll
I/tag00: onScroll
I/tag00: onScroll
I/tag00: onScroll
I/tag00: onScroll
I/tag00: onFling
I/tag00: ================================
I/tag00: onDown
I/tag00: onShowPress
I/tag00: onScroll
I/tag00: onScroll
I/tag00: onFling

GestureDetector.OnDoubleTapListener

双击监听接口,方法如下

  • onSingleTapConfirmed(MotionEvent e):单 击事件。用来判定该次点击是SingleTap而不是DoubleTap,如果连续点击两次就是DoubleTap手势,如果只点击一次,系统等待一段时 间后没有收到第二次点击则判定该次点击为SingleTap而不是DoubleTap,然后触发 SingleTapConfirmed事件。触发顺序 是:OnDown->OnsingleTapUp->OnsingleTapConfirmed ,关于 onSingleTapConfirmed和onSingleTapUp的一点区别: OnGestureListener有这样的一个方法onSingleTapUp,和onSingleTapConfirmed容易混淆。二者的区别 是:onSingleTapUp,只要手抬起就会执行,而对于onSingleTapConfirmed来说,如果双击的话,则 onSingleTapConfirmed不会执行。

  • onDoubleTap(MotionEvent e):双击事件

  • onDoubleTapEvent(MotionEvent e):双击间隔中发生的动作。指触发onDoubleTap以后,在双击之间发生的其它动作,包含down、up和move事件。

    双击所对应的触发事件顺序:

轻轻单击一下,对应的事件触发顺序为:


GestureDetector.SimpleOnGestureListener

它与前两个不同的是:
1、这是一个类,在它基础上新建类的话,要用extends派生而不是用implements继承!
2、 OnGestureListener和OnDoubleTapListener接口里的函数都是强制必须重写的,即使用不到也要重写出来一个空函数但在 SimpleOnGestureListener类的实例或派生类中不必如此,可以根据情况,用到哪个函数就重写哪个函数,因为 SimpleOnGestureListener类本身已经实现了这两个接口的所有函数,只是里面全是空的而已。

介绍的差不多了,那么先来小试牛刀。

package com.example.administrator.myapplication;import android.app.Activity;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.widget.ImageView;
/*** 手势识别类* 图片切换显示,实现接口OnGestureListener* @author Administrator**/
public class MyGestrueTest extends Activity implements OnGestureListener{/**手势管理器*/private GestureDetector detector;/**图片资源数组*/private int [] imageId;/**图片视图*/private ImageView imageView ;private ImageView[] imgView;/**图片下标计数器*/private int count=0;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_my_gestrue_test);//创建手势管理器detector = new GestureDetector(this);//得到图片视图imageView=(ImageView) findViewById(R.id.image_gestrue);//得到图片资源的IdimageId = new int[]{R.drawable.timg,R.drawable.index,R.drawable.index1,R.drawable.img3,R.drawable.img4};//得到图片视图 ImageViewimgView = new ImageView []{(ImageView) findViewById(R.id.small_image1),(ImageView) findViewById(R.id.small_image2),(ImageView) findViewById(R.id.small_image3),(ImageView) findViewById(R.id.small_image4),(ImageView) findViewById(R.id.small_image5)};}@Overridepublic boolean onTouchEvent(MotionEvent event) {//将touch事件交给手势管理器来处理return detector.onTouchEvent(event);}@Overridepublic boolean onDown(MotionEvent e) {return false;}/*** 手势滑动触发的事件*/@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) {//从右往左移动if(e1.getX()-e2.getX()>50){//下标++count++;if(count<=4){//切换到下一张imageView.setImageResource(imageId[count]);imgView[count].setImageResource(R.drawable.ic_launcher1);imgView[count-1].setImageResource(R.mipmap.ic_launcher);}else{//滑动到最后一张,该方向不会再滑动,就停留在最后一张count=4;imageView.setImageResource(imageId[count]);}}//从左往右移动if(e1.getX()-e2.getX()<50){count--;if(count>=0){imageView.setImageResource(imageId[count]);imgView[count].setImageResource(R.drawable.ic_launcher1);imgView[count+1].setImageResource(R.mipmap.ic_launcher);}else{count=0;imageView.setImageResource(imageId[count]);}}return false;}@Overridepublic void onLongPress(MotionEvent e) {}@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,float distanceY) {return false;}@Overridepublic void onShowPress(MotionEvent e) {}@Overridepublic boolean onSingleTapUp(MotionEvent e) {return false;}
}

布局代码:

<?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"android:background="#000"><LinearLayout
        android:id="@+id/my_geture_test_1"android:layout_width="match_parent"android:layout_height="match_parent" ><ImageView
            android:id="@+id/image_gestrue"android:layout_width="match_parent"android:layout_height="match_parent"android:src="@drawable/timg" ></ImageView></LinearLayout><LinearLayout
        android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:gravity="center_horizontal"android:layout_marginBottom="30dp"><ImageView
            android:id="@+id/small_image1"android:padding="5dp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@mipmap/ic_launcher"></ImageView><ImageView
            android:id="@+id/small_image2"android:padding="5dp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@mipmap/ic_launcher" ></ImageView><ImageView
            android:id="@+id/small_image3"android:padding="5dp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@mipmap/ic_launcher" ></ImageView><ImageView
            android:id="@+id/small_image4"android:padding="5dp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@mipmap/ic_launcher" ></ImageView><ImageView
            android:id="@+id/small_image5"android:padding="5dp"android:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@mipmap/ic_launcher" ></ImageView></LinearLayout>
</RelativeLayout>

效果:

可以发现,并没有使用ViewPager这样的控件,虽然没有左右滑动的效果,那个可以在后期优化加上,这里只是做个简单的例子。所以没做太多的优化,毕竟时间有限啊。这是简单的手势识别了。谷歌还提供了自定义手势,通过GestureOverlayView和GestureLibrary增加自定义手势。还提供了缩放手势的识别类ScaleGestureDetector 。之后有时间会继续介绍手势相关。觉得有用,顶一下呗,整理这些内容也不容易~挺花时间的。谢谢大家。

Android基础系列 - 手势识别、运用(一)相关推荐

  1. 重学Android基础系列篇(五):Android虚拟机指令

    前言 本系列文章主要是汇总了一下大佬们的技术文章,属于Android基础部分,作为一名合格的安卓开发工程师,咱们肯定要熟练掌握java和android,本期就来说说这些~ [非商业用途,如有侵权,请告 ...

  2. 重学Android基础系列篇(二):泛型

    前言 本系列文章主要是汇总了一下大佬们的技术文章,属于Android基础部分,作为一名合格的安卓开发工程师,咱们肯定要熟练掌握java和android,本期就来说说这些~ [非商业用途,如有侵权,请告 ...

  3. 史上最详细的Android Studio系列教程四--Gradle基础

    史上最详细的Android Studio系列教程四--Gradle基础 转载于:https://www.cnblogs.com/zhujiabin/p/5125917.html

  4. Android 系统(243)---Android进程系列第一篇---进程基础

    Android进程系列第一篇---进程基础 内容预览.png 概述: 本文主要讲解进程基础,更深入的认识有血有肉的进程,内容涉及进程控制块,信号,进程FD泄露等等.仅供参考,欢迎指正. 一.从Linu ...

  5. Android入门到精通|安卓/Android开发零基础系列Ⅱ【职坐标】-学习笔记(1)-- 常用控件及资源介绍

    前言 为了巩固Android基础知识,回顾一下学习内容,才有此学习笔记. IDE Androdi Studio 4 + Genymotion 创建项目 修改项目的 build.gradle,添加国内镜 ...

  6. Android基础知识巩固系列 Android之四大组件——ContentProvider(内容提供者)

    因为最近要面试,于是打算整理整理一下Android的基础知识,由于之前本人已经学习过大概的Android基础知识,这里主要讲这四大组件.五大存储.六大布局.网络请求等这些内容,其他一些等有时间再整理, ...

  7. Android学习系列(10)--App列表之拖拽ListView(上)

    研究了很久的拖拽ListView的实现,受益良多,特此与尔共飨.       鉴于这部分内容网上的资料少而简陋,而具体的实现过程或许对大家才有帮助,为了详尽而不失真,我们一步一步分析,分成两篇文章. ...

  8. android 菜鸟面单打印_1.0 Android基础入门教程

    本教程于2015年7月开始撰写,耗时半年,总共148节,涵盖了Android基础入门的大部分知识,由于当时能力局限,虽已竭尽全力,但对于一些问题的分析难免有所纰漏,敬请读者海涵!IT技术更新换代很快, ...

  9. Android自定义控件系列--Path综述

    Android自定义控件系列–Path综述 项目源码 点击查看详情 Path 中文 释义为路径 然而它在自定义控件中却有着神一样的着色,这个神,是创造神奇效果的意思 1 Path 的创建 Path p ...

最新文章

  1. SQLBulkCopy 性能统计
  2. docker学习笔记(四)——Dockerfile创建自定义镜像
  3. [转] Spring Boot特性
  4. Software--Architecture--Design
  5. PHP 5.4中的traits特性
  6. JVM用户自定义加载器实现步骤
  7. ASP.NET N问N答 (一) ASP.NET怎么导出到WORD?(把girdview里面的数据到出到word)
  8. Flink 1.12 CDH 6.3 集成
  9. 处理动态SQL语句的参数
  10. 对于软件测试四大误区的认识
  11. PYQT5:基于QsciScintilla的代码编辑器分析10--语法高亮颜色选择
  12. 人脸识别相机对人脸库进行增删改查——MQTT协议
  13. codeforces 934C 区间DP
  14. 解析小型机、大型机和PC服务器间的差别
  15. c语言数学函数指数,C语言数学函数参考表
  16. 外国邮箱排名,共同见证电子邮箱30年的蜕变~
  17. 牛客-紫魔法师(仙人掌染色-判奇环)
  18. python的类,实例,以及实例化
  19. 树莓派简单教程(二)(中)
  20. Windows 10 1809 MSDN 版本下载 ed2k 链接

热门文章

  1. Java通过正则剔除乱码_正则表达式 - 去掉乱码字符/提取字符串中的中文字符/提取字符串中的大小写字母 - Python代码...
  2. 中国工业自动控制系统装置制造运行现状与前景预测分析报告2022年版
  3. 正睿19暑期B班DAY7 数论
  4. 叉车轮胎的种类有哪些?
  5. pig中查询top k,返回每个hour和ad_network_id下最大两个记录(SUBSTRING,order,COUNT_STAR,limit)
  6. 回归本源,勿忘初心,趋势与未来洞察
  7. 2022年熔化焊接与热切割新版试题及熔化焊接与热切割找解析
  8. python读写操作excel数据小应用
  9. 阿里感悟(十)如何写好简历
  10. 现代人工智能的载体——计算机