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 ...
随机推荐
- javascript --- Ajax基础
神马是Ajax? Ajax即‘Asynchronous javascript and XML’(异步javascript和XML),也就是所谓的无刷新页面读取技术. http请求 首先要了解http请 ...
- i++是否原子操作
i++是否原子操作 不是原子操作.理由: 1.i++分为三个阶段: 内存到寄存器 寄存器自增 回内存 这三个阶段中间都可以被中断分离开. 2.++i首先要看编译器是怎么编译的, 某些编译器比如VC在 ...
- Struts2(十六)Json
一.JSON Json就是浏览器和服务器之间交换数据的一种轻量级对象 javaSctipt中类似的对象操作 $(function() { var person = { "name" ...
- iOS--UISearchBar和UISearchDisplayController
UISearchBar继承自UIView.UIResponder.NSObject 属性: autocapitalizationType————自动对输入文本对象进行大小写设置(包含4种类型,但是有时 ...
- iOS 杂笔-20(UIView和CALayer的区别与联系)
iOS 杂笔-20(UIView和CALayer的区别与联系) 每个 UIView 内部都有一个 CALayer 在背后提供内容的绘制和显示,并且 UIView 的尺寸样式都由内部的 Layer 所提 ...
- Web应用程序系统的多用户权限控制设计及实现-首页模块【5】
首页模块就是展示不同权限的最终结果了,在阅读这章之前若有些不明白,可看看后续的单独的权限模块,用户模块,目录模块后从整体上再看首页模块. 阅读该模块需要一定或者是比较熟练的js知识,EasyUI Ta ...
- 多线程基础 (八)NSOperation相关
额外的参考学习可以学习:http://www.cnblogs.com/YouXianMing/p/3707403.html 1.NSOperation简介 NSOperation的作用 配合使用N ...
- 饭团(1):用NABCD大法为项目奠基
上一篇文章:提升效率的开发工具 提到高效的开发工具就像催化剂,加速项目开发.这篇文章提到的NABCD大法,就像一份地图,指引项目往正确的方法上发展. 选择比努力更重要.一个项目成功自然离不开码农们的努 ...
- 安装和配置JDK,并给出安装、配置JDK的步骤。
1.从orcal网站下载安装包. 2.安装目录不要有汉字或空格 3.配置环境变量,增加·JAVA_HOME=jdk的全路径,修改path+%JAVA_HOME%\bin;%JAVA_HOME%\jre ...
- cocos2d-x之场景转换特效
bool HelloWorld::init() { if ( !Layer::init() ) { return false; } Size visibleSize = Director::getIn ...