android 动画之Scroller

android中view的滑动是渐变的,用得比较多的弹性滑动是以下三种:
1. Scroller;
2. Handler#postDelayed;
3. Thread#sleep;

我们现在自定义一个类AutoScrollTextView,需求是传入x移动的距离,当调用它时,这个view水平渐变滑动。

class AutoScrollTextView extends View{
    Scroller scroller = new Scroller(context);

    public void smoothScrollTo(int destX,int duration){
        int scrollX = this.getScrollX();
        int deltaX = destX - scrollX;
        //表示在duration时间内水平滑动deltaX的距离
        scroller.start(scrollX,0,deltaX,0,duration);
        this.invalidate();
    }

    //通过看View的源码,知道View的computeScroll()是空的,这就需要重写我们View中的方法computeScroll()
    @override
    public void computeScroll(){
        if(scroller.computeScrollOffSet()){                     this.scrollTo(scroller.getCurrentX(),scroller.getCurrentY());
            postInvalidate();
        }
    }

    //同理,通过看View的源码,知道View的ondraw()是空的,这就需要我们重新
    @override
    protected void onDraw(){
    super.onDraw();
    computeScroll();
    }
}

从上面看到,我们调用了Scroller的start(),但又调用了View的invalidate(),那里面的具体操作是什么呢?我们来看下scroller这个start()的源码:

public void startScroll(int startX,int startY,int destX,int destY,int duration){
    mMode =  SCROLL_MODE;
    mFinished = false;
    mDuration = duration;
    mStartTime = AnimationUtils.currentAnimationTimeMills();
    mStartX = startX;
    mStartY = startY;
    mFinalX = destX + startX;
    mFinalY = destY + startY;
    mDeltaX = destX;
    mDeltaY = destY;
    mDurationReciprocal = 1.0f/(float)mDuration;
}

我们扯淡的发现,在Scroller的start()方法中,并没有我们期待的滑动操作,只是对一些参数进行了定义~
由此看到,Scroller并不能让view滑动,它只是跟view配合。当在smoothScrollTo()中调用view的invalidate()方法时,就会去调用view的ondraw()方法,而在ondraw()中又不断去调用computeScroll(),而这个computeScroll()在条件允许的情况下,又会不断去调用postInvalidate()方法,如此循环往复,直到条件不允许时,动画也就结束了!
再看下判断条件scroller.computeScrollOffSet()中做了什么:

public boolean computeScrollOffSet(){
    int timePassed = (int)AnimationUtils.currentAnimationTimeMills()-mStartTime;
    if(timePassed < mDuration){
        switch(mMode){
        case SCROLL_MODE:
        final float x = mInterpolator.getInterpolation(timePassed*mDurationReciprocal);
        mCurrentX = mStartX + Math.round(x * mDeltaX);
        mCurrentY = mStartY = Math.round(y * mDeltaY);
        break;
        }
    }

从这里可得知,判断动画是否完成的标志,是mDuration和timePassed的相差值。
Scroller工作原理总结:
Scroller本身并不能实现view的滑动,它需要配合View的computeScroll方法才能完成弹性滑动的效果。它不断让view重绘,而在不断重绘过程中产生一个时间间隔,根据这个时间间隔能得到这个view当前的滑动位置,知道了滑动位置,就可以通过view的scrollTo方法来实现view的滑动。多次的小幅度滑动,就组成了弹性滑动。

你可能感兴趣的:(android)