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的滑动。多次的小幅度滑动,就组成了弹性滑动。