Scroller详解

方法摘要
 void abortAnimation()
           
 boolean computeScrollOffset()
          Call this when you want to know the new location.
 void extendDuration(int extend)
          Extend the scroll animation.
 void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY)
          Start scrolling based on a fling gesture. 甩动
 void forceFinished(boolean finished)
          Force the finished field to a particular value.
 int getCurrX()
          Returns the current X offset in the scroll.
 int getCurrY()
          Returns the current Y offset in the scroll.
 int getDuration()
          Returns how long the scroll event will take, in milliseconds.
 int getFinalX()
          Returns where the scroll will end.
 int getFinalY()
          Returns where the scroll will end.
 int getStartX()
          Returns the start X offset in the scroll.
 int getStartY()
          Returns the start Y offset in the scroll.
 boolean isFinished()
          Returns whether the scroller has finished scrolling.
 void setFinalX(int newX)
           
 void setFinalY(int newY)
           
 void startScroll(int startX, int startY, int dx, int dy)
          Start scrolling by providing a starting point and the distance to travel.
 void startScroll(int startX, int startY, int dx, int dy, int duration)
          Start scrolling by providing a starting point and the distance to travel.
 int timePassed()


详解学习:

 尊重原创作者,转载请注明出处:

http://blog.csdn.net/gemmem/article/details/7321910

  Scroller这个类理解起来有一定的困难,刚开始接触Scroller类的程序员可能无法理解Scroller和View系统是怎么样联系起来的。我经过自己的学习和实践,对Scroller的用法和工作原理有了一定的理解,在这里和大家分享一下,希望大家多多指教。

      首先从源码开始分析:

        View.java

 

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.   /** 
  2.  * Called by a parent to request that a child update its values for mScrollX 
  3.  * and mScrollY if necessary. This will typically be done if the child is 
  4.  * animating a scroll using a {@link android.widget.Scroller Scroller} 
  5.  * object. 
  6.  */  
  7. public void computeScroll()  
  8. {  
  9. }  


    computeScroll是一个空函数,很明显我们需要去实现它,至于做什么,就由我们自己来决定了。

    因为View的子类很多,在下面的例子中,我会在一个自定义的类MyLinearLayout中去实现它。

 

    ViewGroup.java

   

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2. protected void dispatchDraw(Canvas canvas) {  
  3.   
  4.             .......  
  5.   
  6.             .......  
  7.   
  8.             .......  
  9.   
  10.             .......  
  11.   
  12.             for (int i = 0; i < count; i++) {  
  13.             final View child = children[i];  
  14.             if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null)  
  15.   
  16.             {  
  17.                 more |= drawChild(canvas, child, drawingTime);  
  18.             }  
  19.   
  20.             .......  
  21.   
  22.             .......  
  23.   
  24.             .......  


从dispatchDraw函数可以看出,ViewGroup会对它的每个孩子调用drawChild(),  在下面的例子中, ContentLinearLayout的孩子有2个,是2个MyLinearLayout类型的实例。

再看看drawChild函数:

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1.  protected boolean drawChild(Canvas canvas, View child, long drawingTime) {  
  2.   
  3.             ................  
  4.   
  5.             ................  
  6.   
  7.            child.computeScroll();  
  8.   
  9.             ................  
  10.   
  11.             ................  
  12.   
  13. }  

 

看到这里,我想大家应该就明白了,在父容器重画自己的孩子时,它会调用孩子的computScroll方法,也就是说例程中的ContentLinearLayout在调用dispatchDraw()函数时会调用MyLinearLayout的computeScroll方法。

       这个computeScroll()函数正是我们大展身手的地方,在这个函数里我们可以去取得事先设置好的成员变量mScroller中的位置信息、速度信息等等,用这些参数来做我们想做的事情。

       看到这里大家一定迫不及待的想看代码了,代码如下:c

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. package com.yulongfei.scroller;    
  2.     
  3. import android.widget.LinearLayout;    
  4. import android.widget.Scroller;    
  5. import android.app.Activity;    
  6. import android.content.Context;    
  7. import android.graphics.Canvas;    
  8. import android.os.Bundle;    
  9. import android.util.Log;    
  10. import android.view.View;    
  11. import android.widget.Button;    
  12. import android.view.View.OnClickListener;    
  13. import android.view.animation.DecelerateInterpolator;  
  14.     
  15. public class MainActivity extends Activity {    
  16.  private static final String TAG = "TestScrollerActivity";    
  17.     LinearLayout lay1,lay2,lay0;    
  18.      private Scroller mScroller;    
  19.     @Override    
  20.     public void onCreate(Bundle savedInstanceState) {    
  21.         super.onCreate(savedInstanceState);    
  22.         mScroller = new Scroller(thisnew DecelerateInterpolator(2.0F));  
  23.         lay1 = new MyLinearLayout(this);    
  24.         lay2 = new MyLinearLayout(this);    
  25.      
  26.         lay1.setBackgroundColor(this.getResources().getColor(android.R.color.darker_gray));    
  27.         lay2.setBackgroundColor(this.getResources().getColor(android.R.color.white));    
  28.         lay0 = new ContentLinearLayout(this);    
  29.         lay0.setOrientation(LinearLayout.VERTICAL);    
  30.         LinearLayout.LayoutParams p0 = new LinearLayout.LayoutParams    
  31.         (LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.FILL_PARENT);        
  32.         this.setContentView(lay0, p0);    
  33.      
  34.         LinearLayout.LayoutParams p1 = new LinearLayout.LayoutParams    
  35.         (LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.FILL_PARENT);        
  36.         p1.weight=1;    
  37.         lay0.addView(lay1,p1);    
  38.         LinearLayout.LayoutParams p2 = new LinearLayout.LayoutParams    
  39.         (LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.FILL_PARENT);        
  40.         p2.weight=1;    
  41.         lay0.addView(lay2,p2);    

  42.         MyButton btn1 = new MyButton(this);    
  43.         MyButton btn2 = new MyButton(this);    
  44.         btn1.setText("btn in layout1");    
  45.         btn2.setText("btn in layout2");    
  46.         btn1.setOnClickListener(new OnClickListener(){    
  47.             @Override    
  48.             public void onClick(View v) {    
  49.                     mScroller.startScroll(00, -2000500);    
  50.                 }    
  51.         });    
  52.         btn2.setOnClickListener(new OnClickListener(){    
  53.             @Override    
  54.             public void onClick(View v) {    
  55.                     mScroller.startScroll(00, -3000600);    
  56.                 }    
  57.         });    
  58.         lay1.addView(btn1);    
  59.         lay2.addView(btn2);    
  60.         lay0.setLayerType(View.LAYER_TYPE_HARDWARE, null);  
  61.         lay1.setLayerType(View.LAYER_TYPE_SOFTWARE, null);  
  62.         lay2.setLayerType(View.LAYER_TYPE_SOFTWARE, null);  
  63.     }    

  64.     class MyButton extends Button    
  65.     {    
  66.         public MyButton(Context ctx)    
  67.         {    
  68.             super(ctx);    
  69.         }    
  70.         @Override    
  71.         protected void onDraw(Canvas canvas)    
  72.         {    
  73.             super.onDraw(canvas);    
  74.             Log.d("MyButton"this.toString() + " onDraw------");    
  75.         }    
  76.     }    
  77.         
  78.     class MyLinearLayout extends LinearLayout    
  79.     {    
  80.         public MyLinearLayout(Context ctx)    
  81.         {  
  82.             super(ctx);    
  83.         }    
  84.          
  85.         @Override    
  86.         /**  
  87.          * Called by a parent to request that a child update its values for mScrollX  
  88.          * and mScrollY if necessary. This will typically be done if the child is  
  89.          * animating a scroll using a {@link android.widget.Scroller Scroller}  
  90.          * object.  
  91.          */    
  92.         public void computeScroll()     
  93.         {      
  94.             Log.d(TAG, this.toString() + " computeScroll-----------");    
  95.             if(mScroller.computeScrollOffset())//如果mScroller没有调用startScroll,这里将会返回false。    
  96.             {      
  97.                 //因为调用computeScroll函数的是MyLinearLayout实例,    
  98.                 //所以调用scrollTo移动的将是该实例的孩子,也就是MyButton实例    
  99.                 scrollTo(mScroller.getCurrX(), 0);  
  100.                 Log.d(TAG, "getCurrX = " +  mScroller.getCurrX());    
  101.     
  102.                 //继续让系统重绘    
  103.                 //postInvalidate();  
  104.             }    
  105.          }    
  106.     }    
  107.         
  108.     class ContentLinearLayout extends LinearLayout    
  109.     {    
  110.         public ContentLinearLayout(Context ctx)    
  111.         {    
  112.             super(ctx);    
  113.         }    
  114.          
  115.         @Override    
  116.         protected void dispatchDraw(Canvas canvas)    
  117.         {    
  118.             Log.d("ContentLinearLayout""contentview dispatchDraw");    
  119.             super.dispatchDraw(canvas);    
  120.         }    
  121.     }    
  122. }    


      对代码做一个简单介绍:

      例子中定义了2个MyButton实例btn1和btn2,它们将被其父容器MyLinearLayout实例lay1和lay2通过调用scrollTo来移动。

      ContentLinearLayout实例lay0为Activity的contentview,它有2个孩子,分别是lay1和lay2。

      mScroller是一个封装位置和速度等信息的变量,startScroll()函数只是对它的一些成员变量做一些设置,这个设置的唯一效果就是导致mScroller.computeScrollOffset()    返回true。

      这里大家可能有个疑问,既然startScroll()只是虚晃一枪,那scroll的动态效果到底是谁触发的呢?

后面我将给出答案。

 

运行程序,我们来看看Log

点击btn1:

 

点击btn2:



       对照Log,我从button被点击开始,对整个绘制流程进行分析,首先button被点击(这里将回答上文的问题),button的背景将发生变化,这时button将调用invalidate()请求重绘,这就是View系统重绘的源头,即scroll动态效果的触发者。与此同时,mScroller.startScroll被调用了,mScroller在此时被设置了一些有效值。

       好了,既然重绘请求已发出了,那么整个View系统就会来一次自上而下的绘制了,首先输出的Log就是“contentview dispatchDraw”了,它将绘制需要重绘的孩子(lay1和lay2中的一个),接着会调用drawChild,使得computeScroll函数被触发(drawChild里面会调用child.computeScroll()),于是,lay1或者lay2就会以mScroller的位置信息为依据来调用scrollTo了,它的孩子btn1或者btn2就会被移动了。之后又调用了getChildAt(0).invalidate(),这将导致系统不断重绘,直到startScroll中设置的时间耗尽mScroller.computeScrollOffset()返回false才停下来。

       好了,现在整个流程都分析完了,相信大家应该清楚了Scroller类与View系统的关系了吧。理解了Scroller的工作原理,你会发现原来Scroller类并不神秘,甚至有点被动,它除了储存一些数值,什么其他的事情都没做,Scroller类中的一些变量mStartX, mFinalX, mDuration等等的意义也很好理解。


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值