Scroller 只是简单的滑动辅助类,记录滑动的距离、时间等信息。
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
// 滑动模式分为平滑的滑动SCROLL_MODE模式,惯性滑动FLING_MODE模式
mMode = SCROLL_MODE;
//是否结束
mFinished = false;
// 滑动持续时间 ,如果不设置默认250ms
mDuration = duration;
//滑动开始时间
mStartTime = AnimationUtils.currentAnimationTimeMillis();
//滑动x初始值
mStartX = startX;
//滑动y初始值
mStartY = startY;
//x最终值
mFinalX = startX + dx;
//y最终值
mFinalY = startY + dy;
//x改变值
mDeltaX = dx;
//y改变值
mDeltaY = dy;
//单位时间比
mDurationReciprocal = 1.0f / (float) mDuration;
}
从这个方法可以看出只是简单的属性记录而已,没有直接对view进行操作。所以要view调用自己的重绘方法,postInvalidate();或Invalidate()
让view刷新从而调用computeScroll()方法。
我们都知道computeScroll方法一般都是如下写:
public void computeScroll() {
//判断有没有滑动结束
if (mScroller.computeScrollOffset()) {
if (mScroller.getCurrX() == mScroller.getFinalX()) {
countMoveEnd();
} else {
int xPosition = mScroller.getCurrX();
mMove += (mLast - xPosition);
changeMoveAndValue();
mLast = xPosition;
}
}
}
关键就在mScroller.computeScrollOffset()上,该方法实现对滑动距离数据的改变。
public boolean computeScrollOffset() {
//判断是否结束,结束反射false
if (mFinished) {
return false;
}
//获取已经滑动的时间,当前时间减去开始时间
int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
//已经滑动时间是否小于设置滑动总时间
if (timePassed < mDuration) {
switch (mMode) {
case SCROLL_MODE:
//根据Interpolator插值器计算在该时间段里移动的距离加上初始赋值赋值给mCurrX和mCurrY
final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);
mCurrX = mStartX + Math.round(x * mDeltaX);
mCurrY = mStartY + Math.round(x * mDeltaY);
break;
//滑动时,抬起手执行的惯性运动,通过复杂的运算获取当前的mCurrX 、mCurrY 值。
case FLING_MODE:
final float t = (float) timePassed / mDuration;
final int index = (int) (NB_SAMPLES * t);
float distanceCoef = 1.f;
float velocityCoef = 0.f;
if (index < NB_SAMPLES) {
final float t_inf = (float) index / NB_SAMPLES;
final float t_sup = (float) (index + 1) / NB_SAMPLES;
final float d_inf = SPLINE_POSITION[index];
final float d_sup = SPLINE_POSITION[index + 1];
velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
distanceCoef = d_inf + (t - t_inf) * velocityCoef;
}
mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f;
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;
}
如上面的computeScroll方法所述,调用mScroller.computeScrollOffset()修改mCurrY 以及mCurrY 的属性,然后再获取mScroller.getCurrX()的值,进行操作,其中changeMoveAndValue方法中含有postInvalidate()方法,重新绘制页面进而又调用computeScroll方法,直到mScroller.computeScrollOffset()返回false。