OverScroller 是 Scroller 的加强版,增加了滚出视图范围之后的回弹效果,但这个效果最好还是别用了。
OverScroller 是一个辅助类,用来实现视图的平滑滚动。
说道平滑,实质就是利用系统重画的间隔,16ms(实际值),不断重新计算值并重画。无论是使用 ValueAnimator ,还是 OverScroller ,本质都是一样的。
平滑滚动
滚动的实质是移动了画布的原点,所以视图本身的坐标和大小都没发生变化,依旧能触发点击事件。
public class CustomLinearLayout extends LinearLayout {
// ... constructor
OverScroller scroller = new OverScroller(getContext());
public void smoothScroll() {
int increment = 200;
int duration = 300;
scroller.startScroll(0, getScrollY(), 0, increment, duration);
invalidate();
}
@Override
public void computeScroll() {
if (scroller.computeScrollOffset()) {
scrollTo(0, scroller.getCurrY());
}
}
}
case SCROLL_MODE:
// 这个时间是不可修改的
long time = AnimationUtils.currentAnimationTimeMillis();
final long elapsedTime = time - mScrollerX.mStartTime;
final int duration = mScrollerX.mDuration;
if (elapsedTime < duration) {
// 根据过去的时间计算滚动距离,线性插值器就是 Y=X,其他差值器也会经过(0,0) 和(1,1),变的只是趋势。
// q 是一个 0~1 的值。
final float q = mInterpolator.getInterpolation(elapsedTime / (float) duration);
mScrollerX.updateScroll(q);
mScrollerY.updateScroll(q);
} else {
abortAnimation();
}
break;
void updateScroll(float q) {
// 计算时使用的是 float ,精度高;最后的值是 int,因为像素是最小单位。
mCurrentPosition = mStart + Math.round(q * (mFinal - mStart));
}
fling
OverScroller 的另一个功能就是 fling。
平滑滚动是以过去时间到达 duration 作为滚动结束条件的。
fling 则是捕捉一个 fling 事件,获取出初始速度(模拟滑动的惯性),然后设置一定的阻力,计算出速度消减为 0 所需的时间,作为 duration。
fling 的实现很复杂,需要物理和高数的知识(三次样条差值),看不懂。