【转】android手势处理揭秘
当滑动(fling)比移动(scroll)有更高的效率时,为什么要让用户使用scroll操作呢?在面积很小而数据又很多的移动设备上,要显示远在后面的那些内容scroll是很困难的,这种情况下fling更适合。
注:scroll表示手指滑动多少距离,界面跟着显示多少距离,而fling是根据你的滑动方向与轻重,还会自动滑动一段距离。
filing 手势在android交互设计中应用非常广泛:电子书的滑动翻页、ListView滑动删除item、滑动解锁等。所以如何检测用户的fling手势是非 常重要的。但是我们如何获得fling消息呢?如何知道fling的方向,从哪里开始从哪里结束?又如何确定当前手势是fling 而不是scroll?
在我最近的项目Room5中就面临这样的问题,这是一个已经有了的ios项目,现在要做一个android版本。
在 我们处理滑动动画之前,我们需要检测fling事件,对初学者而言,这要比看上去复杂一些。这是因为touch、scroll、fling三个事件之间并 没有明显的界限。scroll总是发生在fling之前,而touch总是发生在scroll之前,滑动屏幕(fling)总是需要先触摸屏幕 (touch)并且在屏幕上移动(scroll)。我们如何知道滑动(fling)没有被touch事件拦截呢?答案是使用几个关于手势 (gesture)处理的类。
我写了一个演示这几个类是如何配合使用的例子程序,你可以在这里得到完整的源码:https://github.com/ericacooksey/FlingDemo 这个demo描述了捕捉fling事件的整个过程。下面是运行apk之后初始界面的截图:
当接收到touch,scroll或者fling事件,事件的名称会显示在界面上,最近发生的显示在最上面。下面是某一次从上往下划动(fling)时,界面上输出的文字:
这幅图给了你关于事件流的一个大概认识:view收到了好几个scroll 事件,每个scroll事件之前都伴随着一个touch事件。scroll事件过程中y轴方向上的速度飞快增长,直到最终fling事件被触发。让我们来看看关键代码, 这里。
首 先,我们实现了View.OnTouchListener来拦截view的touch事件。我这里暂时省略了对滑动速度追踪的代码(省略号),我们将在后 面讨论。这里主要是实现了touch事件触发的时候将会调用的回到方法,将此方法注册给相应的view(这里为TextView),下面是代码片段。
1 mTouchListener = new VelocityTrackingTouchListener(); 2 // Initialize the TextView which will be used to display the logged events 3 mTextView = (TextView) findViewById(R.id.mytextview); 4 mTextView.setOnTouchListener(mTouchListener); 5 private class VelocityTrackingTouchListener implements View.OnTouchListener { 6 @Override 7 public boolean onTouch(View view, MotionEvent motionEvent) { 8 ...... 9 mGestureDetector.onTouchEvent(motionEvent); 10 return true; 11 } 12 }
mGestureDetector 是GestureDetector的实例。onTouch回调方法在将事件派发给view之前接收到了touch事件。任何可能跟touch事件相关的事 件(比如Click)都会被这个回调方法拦截。我们将touch事件交给GestureDetector,因此这里的作用其实就是在将touch事件传递 下去之前,将MotionEvent传递给GestureDetector的onTouchEvent方法,先判断当前到底是什么手势。下面是声明 GestureDetector变量的代码片段:
1 // Instantiate a gesture listener to consume scroll and fling events 2 FlingDetector flingDetector = new FlingDetector(); 3 // Pass the FlingDetector to mGestureDetector to receive the appropriate callbacks 4 mGestureDetector = new GestureDetector(this, flingDetector);
其中FlingDetector是我们继承自SimpleOnGestureListener的一个类。使用SimpleOnGestureListener的好处是它完成了所有对GestureDetector.OnGestureListener所有接口的空实现,因此我们只需重写需要的回调方法。
1 private class FlingDetector extends GestureDetector.SimpleOnGestureListener { 2 public FlingDetector() { 3 super(); 4 } 5 @Override 6 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 7 float velocityY) { 8 updateText("in onFling"); 9 return true; 10 } 11 @Override 12 public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { 13 updateText(String.format("onScroll velocity = (%f, %f)", mTouchListener.xVelocity, mTouchListener.yVelocity)); 14 return false; 15 } 16 }
作为总结,下面是对上面一系列过程的回顾:
(1)view所注册的OnTouchListener拦截了touch事件。
(2)OnTouchListener的回调方法onTouch(View view, MotionEvent motionEvent)将MotionEvent传递给了GestureDetector。
(3)实现一个OnGestureListener,并将他注册给GestureDetector,这样OnGestureListener中处理具体手势的回调方法就能被触发。
注 意OnGestureListener的每个方法都会返回一个boolean值,这个返回值表示当前方法结束之后,MotionEvent是否被“消费” 掉,也就是说是否继续传递下去,true表示被消费掉,反之则没有,可以继续传递。回想上面我们提到的filing发生在scroll之后,scroll 发生在touch之后,而我们希望接收到fling手势,因此我们在onScroll中返回false,在fling中返回true。
但是 现在问题是如果我们希望一个view既可以scroll也可以fling怎么办?比如一个账单界面我们希望sroll查看账单而用fling操作表示 swipe-to-pay。如果你参考上面的fling事件的截图会发现onScroll在onFLing触发之前发生了5次。因此如果我们响应 onScroll事件,那么用户在fling操作的时候会感到不自然,因为scroll的对我们预期的交互产生了干扰。
我们可以直接忽略掉 scroll,将onScroll中的实现留为空,但是这样的话,如果用户手指慢慢滑动查看后面的内容就得不到响应。最好是能在scroll的时候判断这 个scroll是否会导致fling的发生。这种情况下android的VelocityTracker 就派上用场了。先来瞄一眼scroll的时候的手势输出日志:
让我们将这张图中(只有scroll事件的截图)y方向上的速度和上一张图(产生了fling事件的截图)y方向上的速度做一个对比。之所以用y速度是因为两次实验中我们都是从上到下的滑动。
Scroll y-velocity | Fling y-velocity |
---|---|
65 | 30085 |
140 | 23359 |
424 | 13787 |
660 | 10414 |
847 | 7449 |
如你所见, 产生了fling事件的滚动(scroll)事件中y-velocity要比没有产生fling的滚动(scroll)高很多。我们在OnTouchListener的实现中跟踪速度,每收到一个触摸事件就将之添加给 mVelocityTracker
1 switch (action) { 2 case MotionEvent.ACTION_DOWN: 3 if (mVelocityTracker == null) { 4 // Retrieve a new VelocityTracker object to watch the velocity of a motion. 5 mVelocityTracker = VelocityTracker.obtain(); 6 } else { 7 // Reset the velocity tracker back to its initial state. 8 mVelocityTracker.clear(); 9 } 10 // Add a user's movement to the tracker. 11 mVelocityTracker.addMovement(motionEvent); 12 break; 13 case MotionEvent.ACTION_MOVE: 14 mVelocityTracker.addMovement(motionEvent); 15 // When you want to determine the velocity, call 16 // computeCurrentVelocity(). Then call getXVelocity() 17 // and getYVelocity() to retrieve the velocity for each pointer ID. 18 mVelocityTracker.computeCurrentVelocity(1000); 19 // Log velocity of pixels per second 20 xVelocity = mVelocityTracker.getXVelocity(pointerId); 21 yVelocity = mVelocityTracker.getYVelocity(pointerId); 22 break; 23 case MotionEvent.ACTION_CANCEL: 24 // Return a VelocityTracker object back to be re-used by others. 25 mVelocityTracker.recycle(); 26 break; 27 }
然后再将触摸事件传递给FlingDetector去分析,在FlingDetector打印出mVelocityTracker的速度以及对应的状态(scroll还是fling),经过多次实验可以找到一个合理的决定scroll是否会导致fling的临界值。从事判断是否相应onScroll。
转载于:https://www.cnblogs.com/liangstudyhome/p/4170487.html
【转】android手势处理揭秘相关推荐
- 关于《Android应用开发揭秘》中早期版本中联系人例子错误的解决办法
发现目前还有人问这个问题,就在这里在说明一下. 针对于android应用开发揭秘书中的4-5节代码不能工作的补充 首先感谢该篇文章的作者,因为网上到处转载,就不知道原作者了,在这里感谢你对本书的关于与 ...
- 华章揭秘系列精品图书(《Android应用开发揭秘》、《GWT揭秘》、《Spring技术内幕》)...
Android应用开发揭秘(国内首本基于Andriod 2.0的经典著作,5大专业社区一致鼎力推荐!互动网畅销排行榜第1名) 作者:杨丰盛 出版社:机械工业出版社 标准书号:978-7-111-291 ...
- Android手势锁实现
最终效果如下 整体思路 a.自定义了一个RelativeLayout(GestureLockViewGroup)在里面会根据传入的每行的个数,生成多个GestureLockView(就是上面一个个小圈 ...
- Android 系统(74)---Android手势触摸事件的分发和消费机制
Android手势&触摸事件的分发和消费机制 在Android 客户端开发过程中,经常会遇到手势事件的处理,本篇博文讲一下本人对touch事件处理机制的一些理解,希望对一些初级开发者有所帮助. ...
- Android 手势检测实战 打造支持缩放平移的图片预览效果(下)
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/39480503,本文出自:[张鸿洋的博客] 上一篇已经带大家实现了自由的放大缩小图 ...
- android手势_Android手势检测器
android手势 In this tutorial, we'll be discussing and implementing Gestures in our Android Application ...
- android手势_您可能不知道的七个Android手势
android手势 Gestures make using your phone faster and more efficient-but only if you know the gestures ...
- Android手势密码探索
Android 智能手机在全球市场有着极高的市场占有率,越来越受到广大消费者的青睐.但 Android 作为开源操作系统,且很容易可以获得系统 root 权限,Android 系统的安全问题也是用户和 ...
- android手势密码源码,Android自定义UI手势密码改进版源码下载
在之前文章的铺垫下,再为大家分享一篇:Android手势密码,附源码下载,不要错过. 先看第一张图片的布局文件 activity_main.xml xmlns:tools="http://s ...
最新文章
- Material Design Lite,简洁惊艳的前端工具箱。
- 使用SELECT 和OPEN CURSOR 读取big table的性能比较
- UOJ#191. 【集训队互测2016】Unknown
- java utf-8 gbk_Java 字符转码之UTF-8转为GBK/GB2312
- 现代软件工程 第八章 【需求分析】练习与讨论
- 安装R软件(R、studio)的安装包下载官网和教程
- VoIP的原理及技术
- 2018电视剧行业调研报告-趋势篇
- 深度学习常见问题整理
- 数据挖掘:概念与技术 第五章-数据立方体技术
- c/c++回车不换行
- 2022冬-DownKyi 辅助使用的小插件源码分享
- idea 设置编辑器 table 全部显示
- css里给文字加下划线代码,css添加文字下划线样式的方法
- 用wifi实现细粒度的人体感知——Person-in-WiFi: Fine-grained Person Perception using WiFi
- 【Python自学笔记】报错No module Named Wandb
- TextMesh Pro中文字体的动态生成
- 云笔记是干什么用的,看云笔记的优点和使用心得分享
- 屏幕录像功能技术探索及分享
- CSS 样式继承 inherit 属性
热门文章
- .NET完全手动搭建三层B/S架构
- 图结构练习——DFS——判断可达性
- 使用STL的next_permutation函数生成全排列(C++)
- DevOps笔记-07:持续集成,持续交付,持续部署之间的区别
- c++中new和delete的使用方法
- leetcode 35. 搜索插入位置
- Jsp(Java Server Pages)简介
- java spring cloud版b2b2c社交电商spring cloud分布式微服务:分布式配置中心
- 前端技术演进(三):前端安全
- Redis入门第二篇【存储数据结构之string类型】