Scroller的构造函数
public Scroller(Context context) { this(context, null); }
public Scroller(Context context, Interpolator interpolator) { this(context, interpolator, context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB); }
public Scroller(Context context, Interpolator interpolator, boolean flywheel) { mFinished = true; if (interpolator == null) { mInterpolator = new ViscousFluidInterpolator(); } else { mInterpolator = interpolator; } mPpi = context.getResources().getDisplayMetrics().density * 160.0f; mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction()); mFlywheel = flywheel;
mPhysicalCoeff = computeDeceleration(0.84f); // look and feel tuning } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 一般使用第一个构造函数,如果不传入插值器的话,会调用默认的插值器ViscousFluidInterpolator。
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; } 1 2 3 4 5 6 7 8 9 10 11 12 13 保存传进来的各种参数,startX和startY表示滑动开始的起点,mDeltax和mDeltay表示滑动的偏移量。startScroll方法只是用来保存一些数据。在startScroll方法后调用invalidate方法,会导致View重绘,View的draw方法会调用computeScroll方法。在computeScroller方法中,可以调用scrollTo方法,进行View的滑动。scrollTo方法中需要传入的参数,是通过前面调用computeScrollOffset方法完成。
Scroller的computecrollOffset方法
public boolean computeScrollOffset() { if (mFinished) { return false; }
int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
if (timePassed < mDuration) { switch (mMode) { case SCROLL_MODE: ... break; 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; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 首先会计算动画持续时间,小于设置的mDuration时间,执行switch语句。在startScroll方法中的mMode值为SCROLL_MODE,通过插值器判断出移动的距离,并赋值给mCurrX和mCurrY。这样,后续就可以调用getCurrentX方法得到当前坐标值。
Scroller的fling方法
public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) {
if (mFlywheel && !mFinished) { float oldVel = getCurrVelocity();
float dx = (float) (mFinalX - mStartX); float dy = (float) (mFinalY - mStartY); float hyp = FloatMath.sqrt(dx * dx + dy * dy);
float ndx = dx / hyp; float ndy = dy / hyp;
float oldVelocityX = ndx * oldVel; float oldVelocityY = ndy * oldVel; if (Math.signum(velocityX) == Math.signum(oldVelocityX) && Math.signum(velocityY) == Math.signum(oldVelocityY)) { velocityX += oldVelocityX; velocityY += oldVelocityY; } }
mMode = FLING_MODE; mFinished = false;
float velocity = FloatMath.sqrt(velocityX * velocityX + velocityY * velocityY);
mVelocity = velocity;
mDuration = getSplineFlingDuration(velocity); mStartTime = AnimationUtils.currentAnimationTimeMillis(); mStartX = startX; mStartY = startY;
float coeffX = velocity == 0 ? 1.0f : velocityX / velocity; float coeffY = velocity == 0 ? 1.0f : velocityY / velocity;
double totalDistance = getSplineFlingDistance(velocity); mDistance = (int) (totalDistance * Math.signum(velocity));
mMinX = minX; mMaxX = maxX; mMinY = minY; mMaxY = maxY;
mFinalX = startX + (int) Math.round(totalDistance * coeffX); mFinalX = Math.min(mFinalX, mMaxX); mFinalX = Math.max(mFinalX, mMinX);
mFinalY = startY + (int) Math.round(totalDistance * coeffY); mFinalY = Math.min(mFinalY, mMaxY); mFinalY = Math.max(mFinalY, mMinY); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 先判断一次滑动未结束又触发另一次滑动,是否需要累加加速度。设置mMode为FLING_MODE。根据velocityX和 velocityY方法算出总加速度。算出在总加速下可以滑动的距离。最后通过x和y方向上的加速度比值和设定的最大值和最小值给mFinalX或mFinalY赋值。然后调用invalidate方法,最后也会调用computeScrollOffset方法。
public boolean computeScrollOffset() { if (mFinished) { return false; }
int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
if (timePassed < mDuration) { switch (mMode) { case SCROLL_MODE: ... break; 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; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 根据当前滑动时间与总滑动时间的比例。再根据一个SPLINE_POSITION数组计算出了距离系数distanceCoef与加速度系数velocityCoef。再根据这两个系数计算出当前加速度与当前的mCurrX与mCurrY。
最后如果该方法返回了true表示绘制未完成,需要持续的调用invalidate方法和scrollTo方法。返回false,表示绘制完成。 --------------------- 作者:qq_38256015 来源:CSDN 原文:blog.csdn.net/qq_38256015… 版权声明:本文为博主原创文章,转载请附上博文链接! |
|