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。如下代码:
- public class GestureOverlayView extends FrameLayout {
- ...
- private void touchDown(MotionEvent event) {
- ...
- mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));
- ...
- }
- private Rect touchMove(MotionEvent event) {
- ...
- mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime()));
- ...
- }
- private void touchUp(MotionEvent event, boolean cancel) {
- ...
- mCurrentGesture.addStroke(new GestureStroke(mStrokeBuffer));
- ...
- }
- ...
- }
---->通过上面的代码可知,当用户正在绘制手势时,会调用touchDown、touchMove,执行mStrokeBuffer.add(new
GesturePoint(x, y, event.getEventTime())),实现将点的x、y、event.getEventTime() 值作为GesturePoint的构造函数的实参创建GesturePoint对象,然后将得到的GesturePoint添加到mStrokeBuffer集合中(mStrokeBuffer为ArrayList<GesturePoint>类型);
GesturePoint的源代码如下:
- /*
- * Copyright (C) 2008-2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package android.gesture;
- import java.io.DataInputStream;
- import java.io.IOException;
- /**
- * A timed point of a gesture stroke. Multiple points form a stroke.
- */
- //一个手势行程的定时点,多个点形成一个手势行程。GesturePoint封装x,y轴和时间戳的值
- public class GesturePoint {
- public final float x;
- public final float y;
- public final long timestamp;
- public GesturePoint(float x, float y, long t) {
- this.x = x;
- this.y = y;
- timestamp = t;
- }
- //从输入流中读取之前保存在文件中的数据
- static GesturePoint deserialize(DataInputStream in) throws IOException {
- // Read X and Y
- final float x = in.readFloat(); //从输入流中读出对应x轴的坐标值 (来自通过调用GestureStroke的函数serialize保存的,下同)
- final float y = in.readFloat(); //从输入流中读出对应y轴的坐标值
- // Read timestamp
- final long timeStamp = in.readLong(); //从输入流中读出对应的时间戳
- return new GesturePoint(x, y, timeStamp);
- }
- @Override
- public Object clone() {
- return new GesturePoint(x, y, timestamp);
- }
- }
通过源码可知,在GesturePoint的构造函数中,将传进来的点的各个信息值分别赋值给自身的成员变量x、y、timestamp;所以GesturePoint描述的就是组成完成手势中的一个点元素;而GestureOverlayView中的mStrokeBuffer集合保存着组成手势的多数个点
---->紧接着,当用户完成手势绘制手指离开屏幕时,会调用touchUp,执行 mCurrentGesture.addStroke(new
GestureStroke(mStrokeBuffer)),实现将之前绘制手势得到的mStrokeBuffer集合作为GestureStroke构造函数的实参创建GestureStroke对象,然后将GestureStroke对象作为mCurrentGesture(Gesture对象)的方法addStroke的实参,实现将GestureStroke添加到Gesture中;
GesturePoint的部分源代码如下:
- /**
- * A gesture stroke started on a touch down and ended on a touch up. A stroke
- * consists of a sequence of timed points. One or multiple strokes form a gesture.
- */
- public class GestureStroke {
- ...
- public final float length; //length为手势行程的长度
- public final float[] points; //保存组成手势行程的多数个点的x,y坐标值
- private final long[] timestamps;//保存组成手势行程的多数个点的时间戳
- /**
- * A constructor that constructs a gesture stroke from a list of gesture points.
- *
- * @param points
- */
- public GestureStroke(ArrayList<GesturePoint> points) {
- final int count = points.size();
- final float[] tmpPoints = new float[count * 2];
- final long[] times = new long[count];
- RectF bx = null;
- float len = 0;
- int index = 0;
- for (int i = 0; i < count; i++) {
- final GesturePoint p = points.get(i);
- tmpPoints[i * 2] = p.x; //偶数位置保存x值
- tmpPoints[i * 2 + 1] = p.y; //奇数位置保存x值
- times[index] = p.timestamp;
- if (bx == null) {
- bx = new RectF();
- bx.top = p.y;
- bx.left = p.x;
- bx.right = p.x;
- bx.bottom = p.y;
- len = 0;
- } else {
- //Math.pow(a,b)为a的b次方,如Maht.pow(3,2)等于9。下面的公式相当于平方和的根号值
- len += Math.sqrt(Math.pow(p.x - tmpPoints[(i - 1) * 2], 2)
- + Math.pow(p.y - tmpPoints[(i -1 ) * 2 + 1], 2));
- //放大bx覆盖到指定的p.x, p.y点
- bx.union(p.x, p.y);
- }
- index++;
- }
- timestamps = times;
- this.points = tmpPoints;
- boundingBox = bx;
- length = len;
- }
- ...
- }
通过上面的代码可知,当我们创建GestureStroke的对象时,会执行GestureStroke的构造函数。而在GestureStroke的构造函数中,实现将传进来的mStrokeBuffer集合中封存的多个点进行遍历拆解出来,然后分别赋值给GestureStroke的数组成员变量points,timestamps,同时也根据点的坐标值计算出手势行程的长度length;
---->接着,将创建得到的GestureStroke对象通过调用Gesture的addStroke方法添加到Gesture类的mStrokes中,Gesture的addStroke方法源码实现如下:
- /**
- * A gesture is a hand-drawn shape on a touch screen. It can have one or multiple strokes.
- * Each stroke is a sequence of timed points. A user-defined gesture can be recognized by
- * a GestureLibrary.
- */
- /*手势时是触摸屏上手势绘制的形状,它可以单笔画或者多笔画,
- * 每一个笔画是一个计时点序列,用户绘制定义的手势可以通过GestureLibrary来识别
- */
- public class Gesture implements Parcelable {
- ...
- private final ArrayList<GestureStroke> mStrokes = new ArrayList<GestureStroke>();
- ...
- /**
- * Adds a stroke to the gesture.
- *
- * @param stroke
- */
- public void addStroke(GestureStroke stroke) {
- mStrokes.add(stroke);
- ...
- }
- ...
- ...
- }
所以,在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
Android 手势识别类 ( 三 ) GestureDetector 源码浅析的更多相关文章
- Android 手势识别类 ( 二 ) GestureDetector 源码浅析
前言:Android 关于手势的操作提供两种形式:一种是针对用户手指在屏幕上划出的动作而进行移动的检测,这些手势的检测通过android提供的监听器来实现:另一种是用 户手指在屏幕上滑动而形成一定的不 ...
- 16 BasicHashTable基本哈希表类(三)——Live555源码阅读(一)基本组件类
这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 本文由乌合之众 lym瞎编,欢迎转载 http://www.cnblogs.com/oloroso ...
- Android Handler机制(三)----Looper源码解析
一.Looper Looper对象,顾名思义,直译过来就是循环的意思,从MessageQueue中不断取出message. Class used to run a message loop for a ...
- Android 手势识别类 ( 一 ) GestureDetector 基本介绍
为了加强鼠标响应事件,Android提供了GestureDetector手势识别类.通过GestureDetector.OnGestureListener来获取当前被触发的操作手势(Single Ta ...
- Android源码浅析(三)——Android AOSP 5.1.1源码的同步sync和编译make,搭建Samba服务器进行更便捷的烧录刷机
Android源码浅析(三)--Android AOSP 5.1.1源码的同步sync和编译make,搭建Samba服务器进行更便捷的烧录刷机 最近比较忙,而且又要维护自己的博客,视频和公众号,也就没 ...
- Android源码浅析(四)——我在Android开发中常用到的adb命令,Linux命令,源码编译命令
Android源码浅析(四)--我在Android开发中常用到的adb命令,Linux命令,源码编译命令 我自己平时开发的时候积累的一些命令,希望对你有所帮助 adb是什么?: adb的全称为Andr ...
- Android开发之Theme、Style探索及源码浅析
1 背景 前段时间群里有伙伴问到了关于Android开发中Theme与Style的问题,当然,这类东西在网上随便一搜一大把模板,所以关于怎么用的问题我想这里也就不做太多的说明了,我们这里把重点放在理解 ...
- Android源码浅析(五)——关于定制系统,如何给你的Android应用系统签名
Android源码浅析(五)--关于定制系统,如何给你的Android应用系统签名 今天来点简单的我相信很多定制系统的同学都会有一些特定功能的需求,比如 修改系统时间 静默安装 执行某shell命令 ...
- Android源码浅析(二)——Ubuntu Root,Git,VMware Tools,安装输入法,主题美化,Dock,安装JDK和配置环境
Android源码浅析(二)--Ubuntu Root,Git,VMware Tools,安装输入法,主题美化,Dock,安装JDK和配置环境 接着上篇,上片主要是介绍了一些安装工具的小知识点Andr ...
随机推荐
- android ArrayAdapter BaseAdapter SimpleAdapter使用讲解
不是我针对谁,我只想针对新手玩家. 不清楚Adapter作用的可以看一下http://www.cnblogs.com/zhichaobouke/p/5798672.html (括号里的内容都是我主观添 ...
- js判断用户的浏览器设备是移动端还是pc端
最近做的一个网站页面中需要根据用户的访问设备的不同来显示不同的页面样式,主要是判断移动设备还是电脑浏览器访问的. 下面给出js判断处理代码,以作参考. <script type="te ...
- Android Java类编写规范+优化建议
本文仅是我个人在实际开发中习惯的编写方式,当然这种方式也是来自很多官方的推荐,所以在一定程度上是可以被模仿套用的.本文将不定期更新~ 零.指导原则 优先保证可读性,不要过分追求代码艺术和效率 在可读性 ...
- 安卓第六天笔记--ListView
安卓第六天笔记--ListView 1.AdapteView AdapteView 继承ViewGroup它的本质是容器 AdapterView派生了3个子类: AbsListView AbsSpin ...
- Android源码分析之MessageQueue
下面让我们花些时间来看看MessageQueue的具体实现,不过在分析代码之前让我们来理解下在类开头的一大段comments. MessageQueue是比较低层的类,是持有Message(在Loop ...
- OC第一讲:类和对象
今天终于开始进行OC的学习了 一.首先讲了NSLog NSLog是oc里面的输出语句,其用法和printf差不多,但是还是有差别的 1,NSLog是自动换行的,不用像printf那样还需要加'\n': ...
- IOS设计模式-简单工厂
为什么 “简单工厂原理” 叫简单工厂,因为这个工厂类不是抽象类,而是实体类,工厂本身就是一个具体的对象. 写一个例子演示简单工厂模式: >>>>>>>> ...
- Android 实用代码片段
一些不常见确又很实用的代码块. 1.精确获取屏幕尺寸(例如:3.5.4.0.5.0寸屏幕) public static double getScreenPhysicalSize(Activity ct ...
- Effective Java 33 Use EnumMap instead of ordinal indexing
Wrong practice: Putting sets into an array indexed by the type's ordinal /** * Added demo for the &q ...
- 【windows环境下】RabbitMq的安装和监控插件安装
RabbitMq的安装: RabbitMQ是基于Erlang的,所以必须先配置Erlang环境. 下载Erlang,地址:http://www.erlang.org/download/otp_win3 ...