首先,OverScroll
虽然内置了很多看起来像执行滑动效果的方法名,比如startScroll(int, int, int, int)
,springBack(int, int, int, int, int, int)
等等,但是他们并不实际执行滑动效果,只是用于辅助计算,真正的滑动效果需要自己实现。
以startScroll
为例,查看源码可以发现该方法只是设定了动画参数和相关状态,并没有开启动画
void startScroll(int start, int distance, int duration) {
mFinished = false;
mCurrentPosition = mStart = start;
mFinal = start + distance;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mDuration = duration;
// Unused
mDeceleration = 0.0f;
mVelocity = 0;
}
在computeScrollOffset()
源码中,可以更加明显的体会到OverScroll
作为计算辅助类的作用
switch (mMode) {
case SCROLL_MODE:
long time = AnimationUtils.currentAnimationTimeMillis();
// Any scroller can be used for time, since they were started
// together in scroll mode. We use X here.
final long elapsedTime = time - mScrollerX.mStartTime;
final int duration = mScrollerX.mDuration;
if (elapsedTime < duration) {
final float q = mInterpolator.getInterpolation(elapsedTime / (float) duration);
mScrollerX.updateScroll(q);
mScrollerY.updateScroll(q);
} else {
abortAnimation();
}
break;
....
该方法也没有进行实现滑动效果,仅在调用时更新滑动参数。那么又是在哪里实现滑动效果?
View#overScrollBy
对传入的值进行校验:是否超出滚动边界,最后实际调用onOverScrolled(newScrollX, newScrollY, clampedX, clampedY)
由于这个方法参数出其的长,简单说一下各参数的含义
@param deltaX 需要横向滑动的值,单位px
@param scrollX 已经横向滑动过的值,单位px
@param scrollRangeX 最大横向滑动的范围,单位px
@param maxOverScrollX 最大允许超出横向边界值,单位px
@param isTouchEvent 是否由touch event触发
运行记录如下。scrollX表示view当前的位置,deltaX为滑动增量,也即是view将要滑动到的位置。如果允许Over Scroll,那么滑动的范围就是scrollRangeX+maxOverScrollX,到达滑动范围最值后不再滑动。
I/ScrollData: at scrollX:573 with deltaX:0 range is:920 with maxOver:10
I/ScrollData: at scrollX:573 with deltaX:34 range is:920 with maxOver:10
I/ScrollData: at scrollX:607 with deltaX:47 range is:920 with maxOver:10
I/ScrollData: at scrollX:654 with deltaX:40 range is:920 with maxOver:10
I/ScrollData: at scrollX:694 with deltaX:49 range is:920 with maxOver:10
I/ScrollData: at scrollX:743 with deltaX:42 range is:920 with maxOver:10
I/ScrollData: at scrollX:785 with deltaX:43 range is:920 with maxOver:10
I/ScrollData: at scrollX:828 with deltaX:42 range is:920 with maxOver:10
I/ScrollData: at scrollX:870 with deltaX:43 range is:920 with maxOver:10
I/ScrollData: at scrollX:913 with deltaX:40 range is:920 with maxOver:10
I/ScrollData: at scrollX:930 with deltaX:33 range is:920 with maxOver:10
I/ScrollData: at scrollX:930 with deltaX:31 range is:920 with maxOver:10
I/ScrollData: at scrollX:930 with deltaX:28 range is:920 with maxOver:10
I/ScrollData: at scrollX:930 with deltaX:10 range is:920 with maxOver:10
I/ScrollData: at scrollX:930 with deltaX:0 range is:920 with maxOver:10
I/ScrollData: at scrollX:930 with deltaX:-10 range is:920 with maxOver:10
View#onOverScrolled
该方法为了响应overScrollBy()
的调用,但是这个在View里是没有实现的,需要我们自己实现滑动逻辑。
View#scrollTo
是真正实现滑动效果的方法,设置view滚动位置
View#scrollBy
实际调用scrollTo(mScrollX + x, mScrollY + y)
View#computeScroll
源码注释中解释:由父类调用,在必要时更新子类mScrollX 和 mScrollY的值。作用类似于ValueAnimator.AnimatorUpdateListener的功能,由invalidate()调用,用于在动画效果中实时更新mScrollX和mScrollY,并对其做出相应的滑动响应。
startscroll
等,设定动画效果,并开始计算滑动效果中x,y值。注意此时并没有开始滑动动画computeScroll
方法中根据OverScroll计算值,通过scrollTo
等方法,执行实际滑动效果重复执行step.4,step.5知道滑动效果结束。