文档章节

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...

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

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

谷哥的小弟
09/27
0
0
Android Scroller类与computeScroll方法的调用关系

Android ViewGroup中的Scroller与computeScroll的有什么关系? 答:没有直接的关系 知道了答案,是不是意味着下文就没必要看了,如果说对ViewGroup自定义控件不感兴趣,可以不用看了。 1.Sc...

IamOkay
2016/01/10
3K
3

没有更多内容

加载失败,请刷新页面

加载更多

Generator-ES6

基本概念 Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。 Generator 函数有多种理解角度。语法上,首先可以把它理解成,Generator 函数是一个状态机,封装...

简心
9分钟前
2
0
FullCalendar日历插件说明文档

普通显示设置 属性 描述 默认值 header 设置日历头部信息。 如果设置为false,则不显示头部信息。包括left,center,right左中右三个位置,每个位置都可以对应以下不同的配置: title: 显示当...

ada_young
10分钟前
0
0
Redis知识总结--string的内部实现

SDS(Simple Dynamic String) String的数据结构是一个字节数组,但简单的获取数组长度的时间复杂度就是O(n),这对于单线程的redis来讲是不能接受的,因此string在redis中的实现是SDS类,SDS类...

looqy
20分钟前
1
0
SpringBoot开发案例之整合Dubbo分布式服务

前言 在 SpringBoot 很火热的时候,阿里巴巴的分布式框架 Dubbo 不知是处于什么考虑,在停更N年之后终于进行维护了。在之前的微服务中,使用的是当当维护的版本 Dubbox,整合方式也是使用的 ...

Java干货分享
26分钟前
1
0
美团团购订单系统优化记

团购订单系统简介 美团团购订单系统主要作用是支撑美团的团购业务,为上亿美团用户购买、消费提供服务保障。2015年初时,日订单量约400万~500万,同年七夕订单量达到800万。 目标 作为线上S...

Skqing
30分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部