Android 手势识别类 ( 三 ) GestureDetector 源码浅析

简介:

前言:上 篇介绍了提供手势绘制的视图平台GestureOverlayView,但是在视图平台上绘制出的手势,是需要存储以及在必要的利用时加载取出手势。所 以,用户绘制出的一个完整的手势是需要一定的代码机制来完成存储以及必要时加载取出的;那么,在源码中Gesture这个类就是用来描述完整的手势的。一 个Gesture就是用户手指在触摸屏上绘制形成的不规则几何图形(A gesture is a hand-drawn shape on a touch screen);

   一. Gesture的组成

     通过前篇文章<<Android手势源码浅析-----手势绘制(GestureOverlayView)>>的 介绍,我们知道,当我们在GestureOverlayView上绘制手势时,形成的不规则几何图形是由多数个点形成的,这些点都有其对应的在屏幕上的坐 标值和时间戳(event.getEventTime());那么,这些点是如何组成Gesture的呢?针对这个问题,通过对Android手势源码的 浅析来寻求答案;

    下图总体上大概描述了Gesture的形成结构,如下:


   从上图描述的类关系中,可以知道:

      1. 触摸屏上的点首先是通过GesturePoint这个类来描述的,GesturePoint封装点的x,y轴值和时间戳。

      2. GesturePoint中封装的点的信息会在GestureStroke类中被拆解处理,点对应的x,y值被拆解存放在GestureStroke的 float类型数组成员points中,而点对应的时间戳则放在long类型成员数组timestamps中。

      3. GestureStroke表示一个手势行程(用户手指点下屏幕到手势离开屏幕绘制出的轨迹就是一个手势行程)。一个完整的手势由一个或多个手势行程组成(单笔画或多笔画绘制手势)

      4. Gesture由单个或多个GestureStroke组成,Gesture类中的mStrokeBuffer成员为ArrayList类型集合,存放的是GestureStroke;

   二. Gesture的形成过程:

           当我们在GestureOverlayView上绘制手势时,会调用GestureOverlayView的touchDown、touchMove、touchUp方法,然后将通过这个三个方法捕获到的形成手势的多数个点组成Gesture。如下代码:

 

[java]  view plain  copy
  1. public class GestureOverlayView extends FrameLayout {  
  2. ...  
  3.     private void touchDown(MotionEvent event) {  
  4.     ...  
  5.         mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));  
  6.     ...  
  7.     }  
  8.   
  9.     private Rect touchMove(MotionEvent event) {  
  10.     ...  
  11.         mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));  
  12.     ...  
  13.     }  
  14.   
  15.     private void touchUp(MotionEvent event, boolean cancel) {  
  16.     ...  
  17.          mCurrentGesture.addStroke(new GestureStroke(mStrokeBuffer));  
  18.     ...  
  19.     }  
  20. ...  
  21. }  

  ---->通过上面的代码可知,当用户正在绘制手势时,会调用touchDown、touchMove,执行mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime())),实现将点的x、y、event.getEventTime() 值作为GesturePoint的构造函数的实参创建GesturePoint对象,然后将得到的GesturePoint添加到mStrokeBuffer集合中(mStrokeBuffer为ArrayList<GesturePoint>类型);

    GesturePoint的源代码如下:

 

[java]  view plain  copy
  1. /* 
  2.  * Copyright (C) 2008-2009 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16.   
  17. package android.gesture;  
  18.   
  19. import java.io.DataInputStream;  
  20. import java.io.IOException;  
  21.   
  22. /** 
  23.  * A timed point of a gesture stroke. Multiple points form a stroke. 
  24.  */  
  25.   
  26. //一个手势行程的定时点,多个点形成一个手势行程。GesturePoint封装x,y轴和时间戳的值  
  27. public class GesturePoint {  
  28.     public final float x;  
  29.     public final float y;  
  30.   
  31.     public final long timestamp;  
  32.   
  33.     public GesturePoint(float x, float y, long t) {  
  34.         this.x = x;  
  35.         this.y = y;  
  36.         timestamp = t;  
  37.     }  
  38.   
  39.     //从输入流中读取之前保存在文件中的数据  
  40.     static GesturePoint deserialize(DataInputStream in) throws IOException {  
  41.         // Read X and Y  
  42.         final float x = in.readFloat(); //从输入流中读出对应x轴的坐标值 (来自通过调用GestureStroke的函数serialize保存的,下同)  
  43.         final float y = in.readFloat(); //从输入流中读出对应y轴的坐标值  
  44.         // Read timestamp  
  45.         final long timeStamp = in.readLong(); //从输入流中读出对应的时间戳  
  46.         return new GesturePoint(x, y, timeStamp);  
  47.     }  
  48.       
  49.     @Override  
  50.     public Object clone() {  
  51.         return new GesturePoint(x, y, timestamp);  
  52.     }  
  53. }  

   通过源码可知,在GesturePoint的构造函数中,将传进来的点的各个信息值分别赋值给自身的成员变量x、y、timestamp;所以GesturePoint描述的就是组成完成手势中的一个点元素;而GestureOverlayView中的mStrokeBuffer集合保存着组成手势的多数个点

   ---->紧接着,当用户完成手势绘制手指离开屏幕时,会调用touchUp,执行 mCurrentGesture.addStroke(new GestureStroke(mStrokeBuffer)),实现将之前绘制手势得到的mStrokeBuffer集合作为GestureStroke构造函数的实参创建GestureStroke对象,然后将GestureStroke对象作为mCurrentGesture(Gesture对象)的方法addStroke的实参,实现将GestureStroke添加到Gesture中;

    GesturePoint的部分源代码如下:

[java]  view plain  copy
  1. /** 
  2.  * A gesture stroke started on a touch down and ended on a touch up. A stroke 
  3.  * consists of a sequence of timed points. One or multiple strokes form a gesture. 
  4.  */  
  5.   
  6. public class GestureStroke {  
  7. ...  
  8.     public final float length;  //length为手势行程的长度     
  9.     public final float[] points; //保存组成手势行程的多数个点的x,y坐标值   
  10.     private final long[] timestamps;//保存组成手势行程的多数个点的时间戳  
  11.   
  12.     /** 
  13.      * A constructor that constructs a gesture stroke from a list of gesture points. 
  14.      *  
  15.      * @param points 
  16.      */  
  17.     public GestureStroke(ArrayList<GesturePoint> points) {  
  18.         final int count = points.size();  
  19.         final float[] tmpPoints = new float[count * 2];  
  20.         final long[] times = new long[count];  
  21.   
  22.         RectF bx = null;  
  23.         float len = 0;  
  24.         int index = 0;  
  25.   
  26.         for (int i = 0; i < count; i++) {  
  27.             final GesturePoint p = points.get(i);  
  28.             tmpPoints[i * 2] = p.x; //偶数位置保存x值  
  29.             tmpPoints[i * 2 + 1] = p.y; //奇数位置保存x值  
  30.             times[index] = p.timestamp;  
  31.   
  32.             if (bx == null) {  
  33.                 bx = new RectF();  
  34.                 bx.top = p.y;  
  35.                 bx.left = p.x;  
  36.                 bx.right = p.x;  
  37.                 bx.bottom = p.y;  
  38.                 len = 0;  
  39.             } else {  
  40.                 //Math.pow(a,b)为a的b次方,如Maht.pow(3,2)等于9。下面的公式相当于平方和的根号值  
  41.                 len += Math.sqrt(Math.pow(p.x - tmpPoints[(i - 1) * 2], 2)  
  42.                         + Math.pow(p.y - tmpPoints[(i -1 ) * 2 + 1], 2));  
  43.                 //放大bx覆盖到指定的p.x, p.y点  
  44.                 bx.union(p.x, p.y);  
  45.             }  
  46.             index++;  
  47.         }  
  48.           
  49.         timestamps = times;  
  50.         this.points = tmpPoints;  
  51.         boundingBox = bx;  
  52.         length = len;  
  53.     }  
  54. ...  
  55. }  

    通过上面的代码可知,当我们创建GestureStroke的对象时,会执行GestureStroke的构造函数。而在GestureStroke的构造函数中,实现将传进来的mStrokeBuffer集合中封存的多个点进行遍历拆解出来,然后分别赋值给GestureStroke的数组成员变量points,timestamps,同时也根据点的坐标值计算出手势行程的长度length;

   ---->接着,将创建得到的GestureStroke对象通过调用Gesture的addStroke方法添加到Gesture类的mStrokes中,Gesture的addStroke方法源码实现如下:

[java]  view plain  copy
  1. /** 
  2.  * A gesture is a hand-drawn shape on a touch screen. It can have one or multiple strokes. 
  3.  * Each stroke is a sequence of timed points. A user-defined gesture can be recognized by  
  4.  * a GestureLibrary.  
  5.  */  
  6.   
  7. /*手势时是触摸屏上手势绘制的形状,它可以单笔画或者多笔画, 
  8.  * 每一个笔画是一个计时点序列,用户绘制定义的手势可以通过GestureLibrary来识别 
  9.  */  
  10. public class Gesture implements Parcelable {  
  11. ...  
  12.     private final ArrayList<GestureStroke> mStrokes = new ArrayList<GestureStroke>();  
  13.     ...  
  14.     /** 
  15.      * Adds a stroke to the gesture. 
  16.      *  
  17.      * @param stroke 
  18.      */  
  19.     public void addStroke(GestureStroke stroke) {  
  20.         mStrokes.add(stroke);  
  21.         ...  
  22.     }  
  23.     ...  
  24. ...  
  25. }  

     所以,在Gesture的成员mStrokes中存放着是用户在触摸屏上绘制形成的当前手势相关信息。在Gesture中会根据得到的mStrokes 中这些信息去进行一些重要的处理,如将其序列化存储(serialize)、手势转化成bitmap显示(toBitmap)、还原手势的绘制路径 (toPath)等;

    最后,针对手势组成类之间的关系进行一个小结:

    1). GesturePoint: 描述用户手指在屏幕位置的一个定时点,封装用户手指在屏幕上的点坐标值以及时间戳,时间戳由event.getEventTime()决定。

    2). GestureStroke:描述用户手指在屏幕上滑动到手指离开屏幕时所产生的轨迹线(由多个时间序列点形成),一个GestureStroke由多个GesturePoint组成。

    3). Gesture:实现Parcelable接口,描述用户完成绘制的完整手势,一个Gesture由单个或多个GestureStroke组成。手势绘制可通过GestureOverlayView.setGestureStrokeType(inttype)来设置单笔和多笔画。

借鉴:http://blog.csdn.net/stevenhu_223/article/details/9529837



    本文转自 一点点征服   博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/5292533.html,如需转载请自行联系原作者




相关文章
|
3月前
|
Ubuntu 开发工具 Android开发
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
本文介绍了在基于Ubuntu 22.04的环境下配置Python 3.9、安装repo工具、下载和同步AOSP源码包以及处理repo同步错误的详细步骤。
244 0
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
|
1月前
|
JSON 调度 数据库
Android面试之5个Kotlin深度面试题:协程、密封类和高阶函数
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点。文章详细解析了Kotlin中的协程、扩展函数、高阶函数、密封类及`inline`和`reified`关键字在Android开发中的应用,帮助读者更好地理解和使用这些特性。
26 1
|
22天前
|
前端开发 Java 测试技术
android MVP契约类架构模式与MVVM架构模式,哪种架构模式更好?
android MVP契约类架构模式与MVVM架构模式,哪种架构模式更好?
30 0
|
1月前
|
前端开发 Java 测试技术
android MVP契约类架构模式与MVVM架构模式,哪种架构模式更好?
android MVP契约类架构模式与MVVM架构模式,哪种架构模式更好?
22 2
|
3月前
|
开发工具 git 索引
repo sync 更新源码 android-12.0.0_r34, fatal: 不能重置索引文件至版本 ‘v2.27^0‘。
本文描述了在更新AOSP 12源码时遇到的repo同步错误,并提供了通过手动git pull更新repo工具来解决这一问题的方法。
132 1
|
3月前
|
开发工具 uml git
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
本文分享了下载AOSP源码的方法,包括如何使用repo工具和处理常见的repo sync错误,以及配置Python环境以确保顺利同步特定版本的AOSP代码。
474 0
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
|
3月前
|
Java Android开发 芯片
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
本文介绍了如何将基于全志H713芯片的AOSP Android源码导入Android Studio以解决编译和编码问题,通过操作步骤的详细说明,展示了在Android Studio中利用代码提示和补全功能快速定位并修复编译错误的方法。
143 0
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
|
3月前
|
Android开发
我的Android 进阶修炼(1): AOSP源码根目录结构
本文介绍了AOSP源码的根目录结构,提供了基于MTK9269 Android 9.0源码的目录说明,帮助读者了解AOSP源码的组织方式和各目录的功能。
189 0
我的Android 进阶修炼(1): AOSP源码根目录结构
|
3月前
|
开发工具 Android开发 git
全志H713 Android 11 :给AOSP源码,新增一个Product
本文介绍了在全志H713 Android 11平台上新增名为myboard的产品的步骤,包括创建新的device目录、编辑配置文件、新增内核配置、记录差异列表以及编译kernel和Android系统的详细过程。
133 0
|
3月前
|
Ubuntu 开发工具 Android开发
Repo下载、编译AOSP源码:基于Ubuntu 21.04,android-12.1.0_r27
文章记录了作者在Ubuntu 21.04服务器上配置环境、下载并编译基于Android 12.1.0_r27版本的AOSP源码的过程,包括解决编译过程中遇到的问题和错误处理方法。
206 0
下一篇
无影云桌面