前言
一个好的滑动不止能够响应手指的移动,而且还能响应 Fling(抛) 事件,响应手指的移动比较简单,手指移动多少距离,布局就移动多少距离;当快速滑动时,手指离开后,不能马上停止滑动,而是应该计算手指的移动速度,产生一个【抛】(Fling )的动作,让内容继续滚动一段距离。这才是好的滑动组件。那么其中具体的设计究竟是如何呢,今天就来分析一波,借鉴 Android OverScroller 的实现。
Demo
if (mOverScroller.computeScrollOffset()) {
// 获取 scrollY
int y = mOverScroller.getCurrY();
// 此处省略一堆控制滚动的代码
.....
// 更新
postInvalidate();
}
解析
总体逻辑先梳理下,首先内容跟随手指移动而【移动】,手指离开时产生一个 【速度】,根据这个速度计算一个,此次滑动的【总时间】和【总距离】,之后可以计算每一个【时刻】对应的【位置】。那其中时刻与距离的对应关系是如何呢?看了一下 Android 的源码,计算关系之复杂,惨绝人寰,欲研又止!但这不重要,重要的是掌握全局。
一起来欣赏一下代码吧
/*
* Update the current position and velocity for current time. Returns
* true if update has been done and false if animation duration has been
* reached.
*/
boolean update() {
final long time = AnimationUtils.currentAnimationTimeMillis();
final long currentTime = time - mStartTime;
if (currentTime == 0) {
// Skip work but report that we're still going if we have a nonzero duration.
return mDuration > 0;
}
if (currentTime > mDuration) {
return false;
}
double distance = 0.0;
switch (mState) {
case SPLINE: {
final float t = (float) currentTime / mSplineDuration;
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;
}
distance = distanceCoef * mSplineDistance;
mCurrVelocity = velocityCoef * mSplineDistance / mSplineDuration * 1000.0f;
break;
}
case BALLISTIC: {
final float t = currentTime / 1000.0f;
mCurrVelocity = mVelocity + mDeceleration * t;
distance = mVelocity * t + mDeceleration * t * t / 2.0f;
break;
}
.....
}
mCurrentPosition = mStart + (int) Math.round(distance);
return true;
}
mCurrentPosition 就是某个时刻对应的位置,有趣的是 BALLISTIC 模式,还记得高中物理的重力加速度时间与距离的公式吗?是不是似曾相识?这算比较简单的公式,但我们今天但主角是 SPLINE 模式,ScrollView 但滑动正是使用了这个模式进行滑动,体验非常好!!!!公式有点复杂,就不洗洗研究了,喜欢的同学自行研究吧
总结
简单一个滚动,蕴藏的道理生不可测,一不小心就出现了物理知识点......学习还是挺有用的吧