Scroller
官方介绍:Scroller里面封装了滚动操作,并通过收集数据产生滚动动画
1.Scroller的使用
mScroller = new Scroller(context);
public void beginScroll(){
mScroller.startScroll(0,0,-200,0,3000);
invalidate();
}
public void computeScroll() {
if (mScroller.computeScrollOffset()){
scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
postInvalidate();
}
}
从实例代码来看,Scroller
的使用非常简单,初始化一个Scroller
对象,调用startScroll()
方法并invalidate
,然后重写computeScroll()
,调用scrollTo()
方法,并postInvalidate()
。
我们来看下实际运行效果:
简单的几行代码就简单实现了弹性滑动的效果,我已经迫不及待想了解Scroller实现弹性滑动的原理。
2.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;
}
可以看出Scroller
收集了一系列的数据,包括开始坐标,偏移量,滚动时长,以当前时间作为startTime
,并计算出最终坐标。
然后我们来看下computeScroll()
方法
public void computeScroll() {
if (mScroller.computeScrollOffset()){
scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
postInvalidate();
}
}
computeScroll()
方法中,我们先判断了Scroller
是否滚动完毕,然后获取currX
和currY
并作为参数传入到scrollTo()
方法进行滚动操作,并调用postInvalidate()
。
我们继续看下computeScrollOffset
是如何判断滚动是否结束?
public boolean computeScrollOffset() {
if (mFinished) {
return false;
}
int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
if (timePassed < mDuration) {
switch (mMode) {
case SCROLL_MODE:
final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);
mCurrX = mStartX + Math.round(x * mDeltaX);
mCurrY = mStartY + Math.round(x * mDeltaY);
break;
}
else {
mCurrX = mFinalX;
mCurrY = mFinalY;
mFinished = true;
}
return true;
}
而在computeScrollOffset()
方法中,我们通过当前时间和startScroll()
方法中获取的startTime
的时间差来计算得到currX
和currY
,和属性动画里面的插值器原理类似。
computeScroll()
调用了scrollTo
进行瞬间滑动,而弹性滑动我们其实可以理解为连续的瞬间滑动,按照这种理解,computeScroll()
应该每隔一段时间就调用,才会产生弹性滑动的效果,通过查看comuteScroll()
方法的调用链,我们可以看出在draw
方法里调用了computeScroll()
,所以整个流程就很清楚了。
调用startScroll()
方法,然后invalidate()
,导致View
重绘,同时darw()
方法里面会调用computeScroll()
方法,在computeScroll()
方法中,我们首先判断是否滑动完毕,如果没有滑动完毕就计算currX
,currY
,并作为参数传入scrollTo
方法中,然后调用postInvalidta()
方法,而postInvalidate()
也会导致view
重绘,结果就进入到循环状态,直到滚动结束。