android scroller的原理分析

谷歌为什么要设计一个scroller?

Android中所有的的View都有一个实际界面大于可视界面的,这就涉及到界面的移动或者说偏移,View这个类提供了scrollTo和ScrollBy方法来实现界面的滚动,但是这两种滚动都是即刻瞬间的,对于用户来说是不友好的,这个时候就需要一个滚动器来拉长这个滚动过程。也就是我们的Scroller,这个滚动器的构造方法需要一个durration来设置滚动时间。

Scroller的作用的是什么?

实际上Scroller并不负责界面的实际滚动,虽然这个名字让人误解,但实际上它就是一个工具类,它有两个最重要的方法,一个是startScroll(),这个方法就是根据scroller的构造方法中的x,y,distance,durration这些个参数来初始化一些参数,看源码,和我的注释,不必多言:

方法一:

    /**
     * Start scrolling by providing a starting point and the distance to travel.
     * 
     * @param startX Starting horizontal scroll offset in pixels. Positive
     *        numbers will scroll the content to the left.
     * @param startY Starting vertical scroll offset in pixels. Positive numbers
     *        will scroll the content up.
     * @param dx Horizontal distance to travel. Positive numbers will scroll the
     *        content to the left.
     * @param dy Vertical distance to travel. Positive numbers will scroll the
     *        content up.
     * @param duration Duration of the scroll in milliseconds.
     */
    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;

       //重点横坐标=起点坐标与distance的和
        mFinalX = startX + dx;
        mFinalY = startY + dy;
        mDeltaX = dx;
        mDeltaY = dy;

       //持续时间的一个倒数,后面更新滚动后的坐标
        mDurationReciprocal = 1.0f / (float) mDuration;
    }

 

方法二:

 /**
     * Call this when you want to know the new location.  If it returns true,
     * the animation is not yet finished.  loc will be altered to provide the
     * new location.
     */ 
    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);
                final float t_inf = (float) index / NB_SAMPLES;
                final float t_sup = (float) (index + 1) / NB_SAMPLES;
                final float d_inf = SPLINE[index];
                final float d_sup = SPLINE[index + 1];
                final float distanceCoef = d_inf + (t - t_inf) / (t_sup - t_inf) * (d_sup - d_inf);
                
                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;
    }
    

这个方法无需多言,也是更新mCurrY 等状态值。

综上所述,scroller这个类就是一个工具类,get,set一些方法罢了,并不能帮助我们滚动。

 

 

如何实现滚动?

android View类的scrollTo()方法结合Scroller一起使用。具体就是View初始化的时候startScroll,然后去实现每一个ViewGroup中都要实现的一个computeScroll方法,这个方法才是真正控制滚动的方法。我们只需要在我们的ViewGroup中调用这两个方法即可。具体就是copumteScroll中

     if (mScroller.computeScrollOffset()) {//为true的时候说明没有滚动到终点
            if (getScrollX() != mScroller.getCurrX()) {
                scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            }
            invalidate();//scrollTo会导致界面刷新,invalidate()会再一次刷新,这样会形成一个不间断刷新过程
        }

View调用computeScroll的原理及过程?

View draw(Canvas can)有6个过程:

1.绘制bg  

2.保存一些Canvas的layer的状态,为横竖的fadding edge绘制做准备

3.绘制content,也就是调用OnDraw方法来调用View具体的绘图实现。

4.绘制childView,这个是针对ViewGroup的,在View中这个是一个空方法,在ViewGroup中的这个方法中会调用drawChild这个方法,这个方法就会调用computeScroll方法,实现滚动。

5..恢复canvas 的layer状态,绘制fadding edge,

6.绘制scrollBar)

 

转载于:https://my.oschina.net/u/2971691/blog/777313

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值