android scroller的原理分析

来源:互联网 发布:淘宝无法用网银支付 编辑:程序博客网 时间:2024/06/05 11:23

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

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

Scroller的作用的是什么?

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

方法一:

    /**
     * Start scrolling by providing a starting point and thedistance to travel.
     * 
     * @param startX Starting horizontal scroll offset inpixels. Positive
     *        numbers will scroll thecontent 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 numberswill scroll the
     *        content to the left.
     * @param dy Vertical distance to travel. Positive numberswill 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 bealtered 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 floatdistanceCoef = 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.保存一些Canvaslayer的状态,为横竖的fadding edge绘制做准备

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

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

5..恢复canvaslayer状态,绘制faddingedge,

6.绘制scrollBar

 

0 0
原创粉丝点击