文档章节

Scroller源码分析

zhx2012
 zhx2012
发布于 2015/02/04 20:07
字数 1133
阅读 82
收藏 1

1、构造器

    public Scroller(Context context, Interpolator interpolator, boolean flywheel) {
        mFinished = true;
        mInterpolator = interpolator;
        mPpi = context.getResources().getDisplayMetrics().density * 160.0f;
        mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction());
        mFlywheel = flywheel;

        mPhysicalCoeff = computeDeceleration(0.84f); // look and feel tuning
    }

  Scroller有三个构造器,这是最终被调用的,其余两个是

  public Scroller(Context context) {
        this(context, null);
    }
    
    public Scroller(Context context, Interpolator interpolator) {
        this(context, interpolator,
                context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB);
    }

从构造器中,我们可以看到Scroller首干的主要工作时初始化变量:

 mFinished :  判断滚动是否停止,初始化为true

 mInterpolator: 插值器,计算滚动距离、速度的公式、方式,可自定义。

mPpi:像素密度,每英寸所拥有的像素数目,density是像素密度,以160f为基数,可以是160/240/320等。

mDeceleration: 加速度,暂时不知干啥用的。ViewConfiguration保存了超时、尺寸、距离等一些标准常数。保存的一些常数非常有用,比如手指触摸屏幕时的点击和滑动的最低距离。

mFlywheel:暂不知,

mPhysicalCoeff:一个系数。

新建Scroller实例后,最常用的方法之一是 startScroll():

    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;
    }

    这个方法初始化一下变量:

    mMode : SCROLL_MODE  另一个为FLING_MODE。

    mFinished : false,

    mStartTime : AnimationUtils.currentAnimationTimeMillis()

    mStartX : x开始位置

    mStartY : y开始位置

    mFinalX:x结束位置,是x开始位置加上x移动距离  mStartX+dx

    mFinalY:y结束位置,是y开始位置加上y移动距离,mStartY+dy

    mDeltaX:x移动距离

    mDeltaY:y移动距离

    mDurationReciprocal :时间倒数,1/mDuration。

   另一个经常用到的方法是 :

 public boolean computeScrollOffset() {
        if (mFinished) {
            return false;
        }

        int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
    
        if (timePassed < mDuration) {
            switch (mMode) {
            case SCROLL_MODE:
                float x = timePassed * mDurationReciprocal;
    
                if (mInterpolator == null)
                    x = viscousFluid(x); 
                else
                    x = 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 <= mMaxX
                mCurrX = Math.min(mCurrX, mMaxX);
                mCurrX = Math.max(mCurrX, mMinX);
                
                mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
                // Pin to mMinY <= mCurrY <= mMaxY
                mCurrY = 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;
    }

   当想知道最新的控件位置时,可以调用这个方法,如果返回true说明动画还没结束。

   方法入口会判断isFinished 为true说明动画已经结束,返回false。

   if (timePassed < mDuration) {}  判断动画时间是否超时,

   根据mMode计算不同的滚动模式下的位置,

    SCROLL_MODE :  

  float x = timePassed * mDurationReciprocal;

     使用的时间*时间的倒数,得到用时时间百分比。

if (mInterpolator == null)
  x = viscousFluid(x);

   没有设置插值器时,使用默认插值器,设置插值器的话就使用自定义的插值器

  static float viscousFluid(float x)
    {
        x *= sViscousFluidScale;
        if (x < 1.0f) {
            x -= (1.0f - (float)Math.exp(-x));
        } else {
            float start = 0.36787944117f;   // 1/e == exp(-1)
            x = 1.0f - (float)Math.exp(1.0f - x);
            x = start + x * (1.0f - start);
        }
        x *= sViscousFluidNormalize;
        return x;
    }

   代码看不太懂,应该是幂指数相关的。

 mCurrX = mStartX + Math.round(x * mDeltaX);
 mCurrY = mStartY + Math.round(x * mDeltaY);

   计算当前x、y坐标,此时x的类似于距离百分比

   SCROLL_FLING 模式:

    根据固有公式计算速度’和当前x‘y坐标。

    其中如下取值的方法可以借鉴。

 mCurrX = Math.min(mCurrX, mMaxX);
 mCurrX = Math.max(mCurrX, mMinX);


 public final void setFriction(float friction) {
        mDeceleration = computeDeceleration(friction);
        mFlingFriction = friction;
    }

  设置滑动时的摩擦力数量。

public final boolean isFinished() {
        return mFinished;
    }

 返回滚动状态是否结束

    public final void forceFinished(boolean finished) {
        mFinished = finished;
    }

修改isFinished的值

public final int getDuration() {
        return mDuration;
    }

返回滚动消耗的时间

    public final int getCurrX() {
        return mCurrX;
    }

返回当前滚动中x的位置

    public final int getCurrY() {
        return mCurrY;
    }

返回当前滚动中y的位置

    public float getCurrVelocity() {
        return mMode == FLING_MODE ?
                mCurrVelocity : mVelocity - mDeceleration * timePassed() / 2000.0f;
    }

获取当前速率。当前是Fling模式是

public final int getStartX() {
        return mStartX;
    }
    
   
    public final int getStartY() {
        return mStartY;
    }
    
  
    public final int getFinalX() {
        return mFinalX;
    }
    
    
    public final int getFinalY() {
        return mFinalY;
    }

这四个方法分别是返回开始x’y坐标,返回结束x、y坐标

 public void abortAnimation() {
        mCurrX = mFinalX;
        mCurrY = mFinalY;
        mFinished = true;
    }

    终止动画,将当前x,y坐标更新为最终的x、y坐标,并将mFinished置为true标明动画结束

  public void extendDuration(int extend) {
        int passed = timePassed();
        mDuration = passed + extend;
        mDurationReciprocal = 1.0f / mDuration;
        mFinished = false;
    }

   这个方法要注意扩展的时间不是以原来的duration来增加的,而是以使用的时间+扩展的时间




© 著作权归作者所有

zhx2012
粉丝 1
博文 23
码字总数 11497
作品 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
19
0
Android 中 scrollTo | scrollBy | Scroller 的使用

Android Scroller完全解析,关于Scroller你所需知道的一切 本文基于郭神给出的教程(原文地址如上),在结合自己的编码总结这个几个东西的使用。 先来说 scrollTo()与scrollBy()的使用与区别...

a_zhon
2017/12/27
0
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
android scroller的原理分析

谷歌为什么要设计一个scroller? 在Android中所有的的View都有一个实际界面大于可视界面的,这就涉及到界面的移动或者说偏移,View这个类提供了scrollTo和ScrollBy方法来实现界面的滚动,但是...

博为峰教研组
2016/10/28
14
0

没有更多内容

加载失败,请刷新页面

加载更多

3_数组

3_数组

行者终成事
今天
7
0
经典系统设计面试题解析:如何设计TinyURL(二)

原文链接:https://www.educative.io/courses/grokking-the-system-design-interview/m2ygV4E81AR 编者注:本文以一道经典的系统设计面试题:《如何设计TinyURL》的参考答案和解析为例,帮助...

APEMESH
今天
7
0
使用logstash同步MySQL数据到ES

概述   在生成业务常有将MySQL数据同步到ES的需求,如果需要很高的定制化,往往需要开发同步程序用于处理数据。但没有特殊业务需求,官方提供的logstash就很有优势了。   在使用logstas...

zxiaofan666
今天
10
0
X-MSG-IM-分布式信令跟踪能力

经过一周多的鏖战, X-MSG-IM的分布式信令跟踪能力已基本具备, 特点是: 实时. 只有要RX/TX就会实时产生信令跟踪事件, 先入kafka, 再入influxdb待查. 同时提供实时sub/pub接口. 完备. 可以完整...

dev5
今天
7
0
OpenJDK之CyclicBarrier

OpenJDK8,本人看的是openJDK。以前就看过,只是经常忘记,所以记录下 图1 CyclicBarrier是Doug Lea在JDK1.5中引入的,作用就不详细描述了,主要有如下俩个方法使用: await()方法,如果当前线...

克虏伯
今天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部