http://blog.csdn.net/bigconvience/article/details/26735705

http://blog.csdn.net/bigconvience/article/details/26735705

http://blog.csdn.net/bigconvience/article/details/26735705

http://blog.csdn.net/bigconvience/article/details/26735705

代码讲解Android Scroller、VelocityTracker

分类:Android UI 388人阅读 评论(0) 收藏 举报 Android 界面

在编写自定义滑动控件时常常会用到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事件中获取速度,调用流程可如下列所示:

[java] view plain copy
  1. VelocityTrackervTracker=null
  2. @Override
  3. publicbooleanonTouchEvent(MotionEventevent){
  4. intaction=event.getAction();
  5. switch(action){
  6. caseMotionEvent.ACTION_DOWN:
  7. if(vTracker==null){
  8. vTracker=VelocityTracker.obtain();
  9. }else{
  10. vTracker.clear();
  11. }
  12. vTracker.addMovement(event);
  13. break;
  14. caseMotionEvent.ACTION_MOVE:
  15. vTracker.addMovement(event);
  16. //设置单位,1000表示每秒多少像素(pix/second),1代表每微秒多少像素(pix/millisecond)。
  17. vTracker.computeCurrentVelocity(1000);
  18. //从左向右划返回正数,从右向左划返回负数
  19. System.out.println("thexvelocityis"+vTracker.getXVelocity());
  20. //从上往下划返回正数,从下往上划返回负数
  21. System.out.println("theyvelocityis"+vTracker.getYVelocity());
  22. break;
  23. caseMotionEvent.ACTION_UP:
  24. caseMotionEvent.ACTION_CANCEL:
  25. vTracker.recycle();
  26. break;
  27. }
  28. returntrue;
  29. }


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

[java] view plain copy
  1. /**
  2. *CalledbyaparenttorequestthatachildupdateitsvaluesformScrollX
  3. *andmScrollYifnecessary.Thiswilltypicallybedoneifthechildis
  4. *animatingascrollusinga{@linkandroid.widget.ScrollerScroller}
  5. *object.
  6. */
  7. publicvoidcomputeScroll()
  8. {
  9. }
parentView在绘制式,会调用dispatchDraw(Canvas canvas),该函数会调用ViewGroup中的每个子view的boolean draw(Canvas canvas, ViewGroup parent, long drawingTime),用户绘制View,此函数在绘制View的过程中会调用computeScroll()
下面给出一段代码:
[java] view plain copy
  1. @Override
  2. publicvoidcomputeScroll(){
  3. //TODOAuto-generatedmethodstub
  4. Log.e(TAG,"computeScroll");
  5. if(mScroller.computeScrollOffset()){//or!mScroller.isFinished()
  6. Log.e(TAG,mScroller.getCurrX()+"======"+mScroller.getCurrY());
  7. scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
  8. Log.e(TAG,"###getleftis"+getLeft()+"###getRightis"+getRight());
  9. postInvalidate();
  10. }
  11. else
  12. Log.i(TAG,"havedonethescoller-----");
  13. }
这段代码在滑动view之前先调用mScroller.computeScrollOffset()来判断滑动动画是否已结束。computerScrollerOffset()的源代码如下:

[java] view plain copy
  1. /**
  2. *Callthiswhenyouwanttoknowthenewlocation.Ifitreturnstrue,
  3. *theanimationisnotyetfinished.
  4. */
  5. publicbooleancomputeScrollOffset(){
  6. if(mFinished){
  7. returnfalse;
  8. }
  9. //滑动已经持续的时间
  10. inttimePassed=(int)(AnimationUtils.currentAnimationTimeMillis()-mStartTime);
  11. //若在规定时间还未用完,则继续设置新的滑动位置mCurrX和mCurry
  12. if(timePassed<mDuration){
  13. switch(mMode){
  14. caseSCROLL_MODE:
  15. floatx=timePassed*mDurationReciprocal;
  16. if(mInterpolator==null)
  17. x=viscousFluid(x);
  18. else
  19. x=mInterpolator.getInterpolation(x);
  20. mCurrX=mStartX+Math.round(x*mDeltaX);
  21. mCurrY=mStartY+Math.round(x*mDeltaY);
  22. break;
  23. caseFLING_MODE:
  24. finalfloatt=(float)timePassed/mDuration;
  25. finalintindex=(int)(NB_SAMPLES*t);
  26. floatdistanceCoef=1.f;
  27. floatvelocityCoef=0.f;
  28. if(index<NB_SAMPLES){
  29. finalfloatt_inf=(float)index/NB_SAMPLES;
  30. finalfloatt_sup=(float)(index+1)/NB_SAMPLES;
  31. finalfloatd_inf=SPLINE_POSITION[index];
  32. finalfloatd_sup=SPLINE_POSITION[index+1];
  33. velocityCoef=(d_sup-d_inf)/(t_sup-t_inf);
  34. distanceCoef=d_inf+(t-t_inf)*velocityCoef;
  35. }
  36. mCurrVelocity=velocityCoef*mDistance/mDuration*1000.0f;
  37. mCurrX=mStartX+Math.round(distanceCoef*(mFinalX-mStartX));
  38. //PintomMinX<=mCurrX<=mMaxX
  39. mCurrX=Math.min(mCurrX,mMaxX);
  40. mCurrX=Math.max(mCurrX,mMinX);
  41. mCurrY=mStartY+Math.round(distanceCoef*(mFinalY-mStartY));
  42. //PintomMinY<=mCurrY<=mMaxY
  43. mCurrY=Math.min(mCurrY,mMaxY);
  44. mCurrY=Math.max(mCurrY,mMinY);
  45. if(mCurrX==mFinalX&&mCurrY==mFinalY){
  46. mFinished=true;
  47. }
  48. break;
  49. }
  50. }
  51. else{
  52. mCurrX=mFinalX;
  53. mCurrY=mFinalY;
  54. mFinished=true;
  55. }
  56. returntrue;
  57. }
ViewGroup.computeScroll()被调用时机:
当我们执行ontouch或invalidate()或postInvalidate()都会导致这个方法的执行。

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

[java] view plain copy
  1. publicvoidmoveToRightSide(){
  2. if(curScreen<=0){
  3. return;
  4. }
  5. curScreen--;
  6. Log.i(TAG,"----moveToRightSide----curScreen"+curScreen);
  7. mScroller.startScroll((curScreen+1)*getWidth(),0,-getWidth(),0,3000);
  8. scrollTo(curScreen*getWidth(),0);
  9. invalidate();
  10. }
上述代码用到了一个函数:void android.widget.Scroller.startScroll(int startX, int startY, int dx, int dy, int duration)
当startScroll执行过程中即在duration时间内,computeScrollOffset 方法会一直返回true,但当动画执行完成后会返回返加false.
这个函数的源码如下所示,主要用于设置滑动参数

[java] view plain copy
  1. /**
  2. *Startscrollingbyprovidingastartingpoint,thedistancetotravel,
  3. *andthedurationofthescroll.
  4. *
  5. *@paramstartXStartinghorizontalscrolloffsetinpixels.Positive
  6. *numberswillscrollthecontenttotheleft.
  7. *@paramstartYStartingverticalscrolloffsetinpixels.Positivenumbers
  8. *willscrollthecontentup.
  9. *@paramdxHorizontaldistancetotravel.Positivenumberswillscrollthe
  10. *contenttotheleft.
  11. *@paramdyVerticaldistancetotravel.Positivenumberswillscrollthe
  12. *contentup.
  13. *@paramdurationDurationofthescrollinmilliseconds.
  14. */
  15. publicvoidstartScroll(intstartX,intstartY,intdx,intdy,intduration){
  16. mMode=SCROLL_MODE;
  17. mFinished=false;
  18. mDuration=duration;
  19. mStartTime=AnimationUtils.currentAnimationTimeMillis();
  20. mStartX=startX;
  21. mStartY=startY;
  22. mFinalX=startX+dx;
  23. mFinalY=startY+dy;
  24. mDeltaX=dx;
  25. mDeltaY=dy;
  26. mDurationReciprocal=1.0f/(float)mDuration;
  27. }
invalidate()会使得视图重绘,导致parent调用了dispatchDraw(Canvas canvas),然后递归调用child View的draw()函数,该函数又会调用我们定义的computeScroll(), 而这个函数又会调用mScroller.computeScrollOffset()判断动画是否结束,若没结束则继续重绘直到直到startScroll中设置的时间耗尽mScroller.computeScrollOffset()返回false才停下来。

附上完整的实例代码:

自定义Android可滑动控件源码

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







更多 0
0

更多相关文章

  1. Android应用程序启动过程源代码分析(2)
  2. 《Android系统学习》第十章:Android消息处理、消息循环和消息队列
  3. NDK C++线程中如何调用JAVA API
  4. Android(安卓)Audio代码分析23 - attachAuxEffect函数
  5. Android(安卓)服务(本地服务示例)(二)
  6. [Android官方Demo系列] PageTransformer缩放滑动
  7. Android(安卓)Audio代码分析23 - attachAuxEffect函数
  8. 【笔记】android捕获触摸事件
  9. 箭头函数的基础使用

随机推荐

  1. Turn your Android(安卓)phone into a DL
  2. Android动态添加Fragment
  3. Android(安卓)Custom
  4. Android(安卓)studio开发中遇到的一些异
  5. Android(安卓)工具类
  6. android视频播放的代码
  7. [Android拾怡]弱化Java方法返回值类型
  8. android位置服务
  9. Android简单、美观而且十分强大的日志工
  10. android SpannableString使用详解