文档章节

Scroller详解

k
 kim366
发布于 2016/05/13 19:13
字数 1576
阅读 1
收藏 0
方法摘要
 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 派生到我的代码片
  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 派生到我的代码片
  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 派生到我的代码片
  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 派生到我的代码片
  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等等的意义也很好理解。


本文转载自:http://blog.csdn.net/oyangyujun/article/details/48025801

共有 人打赏支持
上一篇: 新的征途
k
粉丝 1
博文 129
码字总数 0
作品 0
朝阳
私信 提问
Android Scroller

Android Scroller实现View弹性滑动完全解析() http://www.jianshu.com/p/9419262a342a# Android Scroller简单用法 http://ipjmc.iteye.com/blog/1615828 Android Scroller完全解析,关于Scr......

addcn
2016/06/20
17
0
Android 滑动效果高级篇(八)—— 自定义控件

自定义控件,较常用View、ViewGroup、Scroller三个类,其继承关系如下: 本示例自定义控件,实现一个Gallery效果,并添加了一个显示View个数和位置的bar条,效果图: 自定义控件,包含通过继...

长平狐
2013/01/06
1K
0
C语言自学完备手册(21)——递归

版权声明: https://blog.csdn.net/lfdfhl/article/details/82897146 自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–o...

谷哥的小弟
2018/09/29
0
0
C语言自学完备手册(19)——冒泡排序

版权声明: https://blog.csdn.net/lfdfhl/article/details/82862688 自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–o...

谷哥的小弟
2018/09/27
0
0
Could not find com.android.tools.build:gradle:3.0.1

版权声明: https://blog.csdn.net/lfdfhl/article/details/84191614 自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–o...

谷哥的小弟
2018/11/17
0
0

没有更多内容

加载失败,请刷新页面

加载更多

二进制相关

二进制 众所周知计算机使用的是二进制,数字的二进制是如何表示的呢? 实际就是逢二进一。比如 2 用二进制就是 10。那么根据此可以推算出 5的二进制等于 10*10+1 即为 101。 在计算机中,负数以...

NotFound403
昨天
2
0
day22:

1、写一个getinterface.sh 脚本可以接受选项[i,I],完成下面任务: 1)使用格式:getinterface.sh [-i interface | -I ip] 2)当用户使用-i选项时,显示指定网卡的IP地址;当用户使用-I选项...

芬野de博客
昨天
1
0
Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现

自Spring Cloud Alibaba发布第一个Release以来,就备受国内开发者的高度关注。虽然Spring Cloud Alibaba还没能纳入Spring Cloud的主版本管理中,但是凭借阿里中间件团队的背景,还是得到不少...

程序猿DD
昨天
3
0
Java并发编程:深入剖析ThreadLocal

ThreadLocal 的理解 ThreadLocal,很多地方叫线程本地变量,或线程本地存储。ThreadLocal为变量在每个线程中都创建了一个副本,每个线程可以访问自己内部的副本变量。===》解决的问题是线程间...

细节探索者
昨天
2
0
【Python3之异常处理】

一、错误和异常 1.错误 代码运行前的语法或者逻辑错误 语法错误(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正) def test: ^SyntaxError: invalid...

dragon_tech
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部