当前位置: 首页 > 编程日记 > 正文

代码解说Android Scroller、VelocityTracker

在编写自己定义滑动控件时经常会用到Android触摸机制和Scroller及VelocityTracker。Android Touch系统简单介绍(二):实例具体解释onInterceptTouchEvent与onTouchEvent的调用过程对Android触摸机制须要用到的函数进行了具体的解释。本文主要介绍两个重要的类:Scroller及VelocityTracker。利用上述知识,最后给出了一个自己定义滑动控件的demo,该demo类似于ImageGallery。

ImageGallery通常是用GridView来实现的,能够左右滑动。本样例实现的控件直接继承一个ViewGroup,对其回调函数如 onTouchEvent、onInterceptTouchEvent、computeScroll等进行重载。弄懂该代码。对Android touch的认识将会更深一层。

VelocityTracker:用于对触摸点的速度跟踪,方便获取触摸点的速度。
使用方法:一般在onTouchEvent事件中被调用。先在down事件中获取一个VecolityTracker对象,然后在move或up事件中获取速度,调用流程可例如以下列所看到的:

VelocityTracker vTracker = null;
@Override  
public boolean onTouchEvent(MotionEvent event){  int action = event.getAction();  switch(action){  case MotionEvent.ACTION_DOWN:  if(vTracker == null){  vTracker = VelocityTracker.obtain();  }else{  vTracker.clear();  }  vTracker.addMovement(event);  break;  case MotionEvent.ACTION_MOVE:  vTracker.addMovement(event);  //设置单位,1000 表示每秒多少像素(pix/second),1代表每微秒多少像素(pix/millisecond)。 vTracker.computeCurrentVelocity(1000);  //从左向右划返回正数,从右向左划返回负数System.out.println("the x velocity is "+vTracker.getXVelocity());  //从上往下划返回正数,从下往上划返回负数System.out.println("the y velocity is "+vTracker.getYVelocity());  break;  case MotionEvent.ACTION_UP:  case MotionEvent.ACTION_CANCEL:  vTracker.recycle();  break;  }  return true;  
}  


Scroller:用于跟踪控件滑动的轨迹。此类不会移动控件,须要你在View的一个回调函数computerScroll()中使用Scroller对象还获取滑动的数据来控制某个View。

  /*** Called by a parent to request that a child update its values for mScrollX* and mScrollY if necessary. This will typically be done if the child is* animating a scroll using a {@link android.widget.Scroller Scroller}* object.*/
public void computeScroll()
{
}
parentView在绘制式。会调用dispatchDraw(Canvas canvas),该函数会调用ViewGroup中的每一个子view的boolean draw(Canvas canvas, ViewGroup parent, long drawingTime),用户绘制View,此函数在绘制View的过程中会调用computeScroll()
以下给出一段代码:
@Override
public void computeScroll() {	// TODO Auto-generated method stubLog.e(TAG, "computeScroll");if (mScroller.computeScrollOffset()) { //or !mScroller.isFinished()Log.e(TAG, mScroller.getCurrX() + "======" + mScroller.getCurrY());scrollTo(mScroller.getCurrX(), mScroller.getCurrY());Log.e(TAG, "### getleft is " + getLeft() + " ### getRight is " + getRight());postInvalidate();}elseLog.i(TAG, "have done the scoller -----");
}
这段代码在滑动view之前先调用mScroller.computeScrollOffset()来推断滑动动画是否已结束。computerScrollerOffset()的源码例如以下:

/*** Call this when you want to know the new location.  If it returns true,* the animation is not yet finished.*/ 
public boolean computeScrollOffset() {if (mFinished) {return false;}//滑动已经持续的时间int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);//若在规定时间还未用完,则继续设置新的滑动位置mCurrX和mCurryif (timePassed < mDuration) {switch (mMode) {case SCROLL_MODE:float x = timePassed * mDurationReciprocal;if (mInterpolator == null)x = viscousFluid(x); elsex = mInterpolator.getInterpolation(x);mCurrX = mStartX + Math.round(x * mDeltaX);mCurrY = mStartY + Math.round(x * mDeltaY);break;case FLING_MODE:final float t = (float) timePassed / mDuration;final int index = (int) (NB_SAMPLES * t);float distanceCoef = 1.f;float velocityCoef = 0.f;if (index < NB_SAMPLES) {final float t_inf = (float) index / NB_SAMPLES;final float t_sup = (float) (index + 1) / NB_SAMPLES;final float d_inf = SPLINE_POSITION[index];final float d_sup = SPLINE_POSITION[index + 1];velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);distanceCoef = d_inf + (t - t_inf) * velocityCoef;}mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f;mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));// Pin to mMinX <= mCurrX <= mMaxXmCurrX = Math.min(mCurrX, mMaxX);mCurrX = Math.max(mCurrX, mMinX);mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));// Pin to mMinY <= mCurrY <= mMaxYmCurrY = Math.min(mCurrY, mMaxY);mCurrY = Math.max(mCurrY, mMinY);if (mCurrX == mFinalX && mCurrY == mFinalY) {mFinished = true;}break;}}else {mCurrX = mFinalX;mCurrY = mFinalY;mFinished = true;}return true;
}
ViewGroup.computeScroll()被调用时机:
当我们运行ontouch或invalidate()或postInvalidate()都会导致这种方法的运行。

我们在开发控件时。常会有这种需求:当单机某个button时。某个图片会在规定的时间内滑出窗体。而不是一下子进入窗体。实现这个功能能够使用Scroller来实现。
以下给出一段代码,该代码控制下一个界面在3秒时间内缓慢进入的效果。

public void moveToRightSide(){if (curScreen <= 0) {return;}curScreen-- ;Log.i(TAG, "----moveToRightSide---- curScreen " + curScreen);mScroller.startScroll((curScreen + 1) * getWidth(), 0, -getWidth(), 0, 3000);scrollTo(curScreen * getWidth(), 0);invalidate();
}
上述代码用到了一个函数:void android.widget.Scroller.startScroll(int startX, int startY, int dx, int dy, int duration)
当startScroll运行过程中即在duration时间内,computeScrollOffset  方法会一直返回true,但当动画运行完毕后会返回返加false.
这个函数的源代码例如以下所看到的,主要用于设置滑动參数

/*** Start scrolling by providing a starting point, the distance to travel,* and the duration of the scroll.* * @param startX Starting horizontal scroll offset in pixels. Positive*        numbers will scroll the content to the left.* @param startY Starting vertical scroll offset in pixels. Positive numbers*        will scroll the content up.* @param dx Horizontal distance to travel. Positive numbers will scroll the*        content to the left.* @param dy Vertical distance to travel. Positive numbers will scroll the*        content up.* @param duration Duration of the scroll in milliseconds.*/
public void startScroll(int startX, int startY, int dx, int dy, int duration) {mMode = SCROLL_MODE;mFinished = false;mDuration = duration;mStartTime = AnimationUtils.currentAnimationTimeMillis();mStartX = startX;mStartY = startY;mFinalX = startX + dx;mFinalY = startY + dy;mDeltaX = dx;mDeltaY = dy;mDurationReciprocal = 1.0f / (float) mDuration;
}
invalidate()会使得视图重绘,导致parent调用了dispatchDraw(Canvas canvas),然后递归调用child View的draw()函数。该函数又会调用我们定义的computeScroll(), 而这个函数又会调用mScroller.computeScrollOffset()推断动画是否结束。若没结束则继续重绘直到直到startScroll中设置的时间耗尽mScroller.computeScrollOffset()返回false才停下来。

附上完整的实例代码:

自己定义Android可滑动控件源代码

执行效果图例如以下,滑动屏幕会显示不同的图片。







相关文章:

写给云栖社区在做网站的朋友一点干货

我本人也是从事网站建设及APP开发业务的&#xff0c;工作多年下来&#xff0c;从以前的几百元企业网站&#xff0c;到商城网站&#xff0c;以及一些应用类型的APP开发&#xff0c;亲眼目睹了很多企业&#xff0c;以及很多项目&#xff0c;在应用的过程中&#xff0c;过了1-2年&…

Strategy_Requirement2

以下代码是“策略模式”的第二个例子&#xff1a;

如何启用SQL Server 2008的FILESTREAM特性

如何启用SQL Server 2008的FILESTREAM特性 今天安装SQL Server 2008的时候没有注意&#xff0c;忘记了启用FILESTREAM特性&#xff0c;因为默认情况下FILESTREAM是禁用的。安装完成后&#xff0c;再导入一个.bak的备份数据库时提示FILESTREAM feature is disabled&#xff0c;到…

如何在搜索结果出来之前,让页面显示“等待中。。。”

在当前页面点击搜索按纽后&#xff0c;当前页的button onclick事件会生成一个sql语句&#xff0c;然后转到查询结果页面&#xff0c;由于查询可能很费时间&#xff0c;客户要求在这两个页面中加入一个提示用户正在查询&#xff0c;请等待的页&#xff0c;具体的查询是在查询结果…

Strategy_Level1

以下代码是“策略模式”的第三个例子&#xff1a;

波士顿房价预测学习项目笔记

机器学习入门项目 作为机器学习的入门项目&#xff0c;了解到这个一个监督学习类型的回归问题模型。项目中需要根据已有的数据&#xff0c;构建一个合理的模型对未来的房价可以做出预测。 Udacity机器学习课程针对初学者做了精心地设计&#xff0c;这里来看项目是如何组织的&am…

LINQ之路19:LINQ to XML之X-DOM更新、和Value属性交互

本篇包含两部分内容&#xff1a;X-DOM更新一节中我们会详细讨论LINQ to XML的更新方式&#xff0c;包括Value的更新、子节点和属性的更新、通过Parent节点实现更新&#xff1b; 和Value属性交互一节会详细讨论XElement和XAttribute的Value属性。如果一个元素只有单个XText子节点…

明朝是中国历史上最有骨气的王朝?【ZZ】

linked from http://www.guoxue.com/article/list.asp?id6095明朝是中国历史上最有骨气的王朝&#xff1f;作者&#xff1a; &#xff08;国学网2006-5-12发布&#xff09; 有人对明朝极尽污蔑之能事&#xff0c;好象明朝是最不中用的朝代。其实&#xff0c;只要细心比较&am…

马哥第七次作业

系统的INPUT和OUTPUT默认策略为DROP&#xff0c;请完成以下关于iptables的题目&#xff1b;1、限制本地主机的web服务器在周一不允许访问&#xff1b;新请求的速率不能超过100个每秒&#xff1b;web服务器包含了admin字符串的页面不允许访问&#xff1b;web服务器仅允许响应报文…

Strategy_Pattern

以下代码是“策略模式”的第四个例子&#xff1a;

JAVA-基础(Class对象及反射)

JAVA-基础&#xff08;Class对象及反射&#xff09; 1.&#xff08;1&#xff09;什么是class对象&#xff1f; 首先&#xff0c;java有两种对象&#xff0c;第一种是实例对象&#xff0c;第二种是Class对象&#xff0c;每一个类运行的类型信息就是用Class对象表示的&#xff0…

当年学生的一件事,心情很难过

当年学生的一件事&#xff0c;心情很难过 今天同一个以前的学生聊天&#xff0c;搞得心情很难过。那年是刚毕业&#xff0c;带了几个学生的毕业论文&#xff0c;其中有一个&#xff0c;只是第一次见过一面&#xff0c;最后答辩前见一两天以及答谢见过一面。他从来不同我联系&am…

while循环中,break,continue,return的差别

break 结束循环&#xff0c;跳出循环体&#xff1b;continue 结束本次循环。进行下次循环&#xff1b;return 跳出循环体所在的方法&#xff0c;相当于跳出循环体。

Strategy_Level2

以下代码是“策略模式”的第五个例子&#xff1a;

自制绘图之坐标轴

写代码之前得先了解坐标轴的一些属性&#xff0c;坐标轴有范围&#xff0c;每隔多少显示一条数值信息。然而间隔信息有时并不确定&#xff0c;一旦设置不准确&#xff0c;图形会乱掉。最好的方法是使用另一个参数&#xff1a;分隔符总数。这样可以利用坐标范围计算出间隔。 首先…

DotNET(C#) Socket基本编程 (1)

Socket基本编程 服务端&#xff1a; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; Thread mythread ; Socket socket; // 清理所有正在使用的资源。 protected override void Dispose( bool disposing ) { try {    socket.Clos…

CC2540 OSAL 学习其中原理,以及 给任务 添加 一个事件(定时发送串口消息)

参考学习大神博客&#xff1a; http://blog.csdn.net/feilusia/article/details/51083953 &#xff1a; http://blog.csdn.net/xiaoleiacmer/article/details/41723583 1、TI 的 CC2540跑了一个 OSAL (Operating System Abstraction Layer) 心得&#xff1a;大概 就是 一个循…

Strategy_Level3

以下代码是“策略模式”的第六个例子&#xff1a;

SDK开发日积月累(二)

WM_NOTIFY消息和WM_COMMAND消息在一个对话框中&#xff0c;子控件可以有两种方式与父对话框通信。1.向父对话框发送WM_COMMAND消息&#xff0c;但这种消息传递的信息量比较少。2.向父对话框发送WM_NOTIFY消息&#xff0c;信息量比较大。idCtrl (int) wParam; pnmh (LPNMHDR) …

关于IP地址的分类

我们说过因特网是把全世界的无数个网络连接起来的一个庞大的网间网&#xff0c;每个网络中的计算机通过其自身的IP地址而被唯一标识的&#xff0c;据此我们也可以设想&#xff0c;在INTERNET上这个庞大的网间网中&#xff0c;每个网络也有自己的标识符。这与我们日常生活中的电…

Visual Studio UML Activity Diagram(1)

数理系LSGO软件技术团队能够存活下来&#xff0c;并形成战斗力的根本原因&#xff0c;归结为我们的价值观。我们“只问收获&#xff0c;不问耕耘”&#xff0c;对知识是贪婪的&#xff0c;我们会把所学的知识放到场景中去应用&#xff0c;我们一定要做出成品。我们强调“要构建…

VMware 克隆Linux后找不到eth0

VMware 克隆Linux,ifconfig 不出现eth0解决方案:1)删除 /etc/udev/rules.d/70-persistent-net.rules/rm -rf /etc/udev/rules.d/70-persistent-net.rules2)重启init 6 3)ifconfig 查看转载于:https://blog.51cto.com/ictedu/1917185

笔试算法题(58):二分查找树性能分析(Binary Search Tree Performance Analysis)

议题&#xff1a;二分查找树性能分析&#xff08;Binary Search Tree Performance Analysis&#xff09; 分析&#xff1a; 二叉搜索树&#xff08;Binary Search Tree&#xff0c;BST&#xff09;是一颗典型的二叉树&#xff0c;同时任何节点的键值大于等于该节点左子树中的所…

定义自定义的异常

首先我们建立自己的异常类CustomException&#xff0c;它要继承自ApplicationException类&#xff08;这是一个在发生非致命的应用程序错误时抛出的通用异常&#xff0c;它又继承于更为通用的Exception类&#xff09;&#xff0c;将其用作为应用程序定义的任何自定义异常的基类…

python3 的 round 函数的 练习

python3 的 round 函数感觉很别扭&#xff0c;其运算结果与习惯不相符。特记录下来&#xff1a; 代码 python 3的 round 函数 是“四舍六入五成双”的https://www.zhihu.com/question/20128906print(python 3的 round 函数&#xff1a;四舍六入五成双)print(\nround(-3.5) , …

Visual Studio UML Activity Diagram(2)

昨天的图文介绍了Visual Studio UML Activity Diagram中所涉及的对象&#xff0c;今天图文我们来介绍这些对象的属性部分并给出UML关于Activity Diagram的元模型类图。通常情况下&#xff0c;我们在做一套软件系统的时候&#xff0c;对甲方业务流程并不熟悉&#xff0c;如果直接…

Go 语言中手动内存管理

2019独角兽企业重金招聘Python工程师标准>>> Go 语言是自带GC的, 相对C语言等的手动内存管理省事很多, 弊端便是会消耗更多的内存, 以及在GC时导致整个程序的停顿. 在某些特殊场合, 如果能够可选地手动进行内存管理, 效果会好不少. Go 目前的 GC 实现比较简单(mark-…

依赖倒转原则(Dependency Inversion Principle,DIP)

前面两篇图文介绍了“开闭原则”和“里氏替换原则”。开发出对扩展开放&#xff0c;对修改封闭的系统是程序员的目标&#xff0c;而今天所介绍的“依赖倒转原则”正是实现这一目标的途径之一&#xff0c;而“里氏替换原则”为这一途径提供了保证。大家或许发现&#xff0c;我写…

细说浏览器特性检测(2)-通用事件检测

在上一篇中介绍了jQuery1.4版本新增的几个浏览器特性检测方案和具体的目的&#xff0c;本文将以事件为中心&#xff0c;介绍一个较为完整、通用的事件检测方案。 事件检测&#xff0c;即检测某一事件在不同的浏览器中是否存在&#xff08;可用&#xff09;&#xff0c;这在编写…

robot简单功能测试脚本设计(例子)

以学生管理系统的添加一个学生信息为例子页面对象&#xff1a;editbox&#xff08;姓名&#xff09;,button&#xff08;添加&#xff09;数据要求&#xff1a;1 姓名不能为空2 姓名不能重复程序结构1 点button&#xff0c;弹出对话框“姓名不能为空”2 输入姓名&#xff0c;点…