Android Scroller类介绍

资料:http://blog.csdn.net/gemmem/article/details/7321910

Scroller源码:

  1 /*
  2  * Copyright (C) 2006 The Android Open Source Project
  3  *
  4  * Licensed under the Apache License, Version 2.0 (the "License");
  5  * you may not use this file except in compliance with the License.
  6  * You may obtain a copy of the License at
  7  *
  8  *      http://www.apache.org/licenses/LICENSE-2.0
  9  *
 10  * Unless required by applicable law or agreed to in writing, software
 11  * distributed under the License is distributed on an "AS IS" BASIS,
 12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  * See the License for the specific language governing permissions and
 14  * limitations under the License.
 15  */
 16 
 17 package android.widget;
 18 
 19 import android.content.Context;
 20 import android.hardware.SensorManager;
 21 import android.os.Build;
 22 import android.util.FloatMath;
 23 import android.view.ViewConfiguration;
 24 import android.view.animation.AnimationUtils;
 25 import android.view.animation.Interpolator;
 26 
 27 
 28 /**
 29  * This class encapsulates scrolling.  The duration of the scroll
 30  * can be passed in the constructor and specifies the maximum time that
 31  * the scrolling animation should take.  Past this time, the scrolling is 
 32  * automatically moved to its final stage and computeScrollOffset()
 33  * will always return false to indicate that scrolling is over.
 34  */
 35 public class Scroller  {
 36     private int mMode;
 37 
 38     private int mStartX;
 39     private int mStartY;
 40     private int mFinalX;
 41     private int mFinalY;
 42 
 43     private int mMinX;
 44     private int mMaxX;
 45     private int mMinY;
 46     private int mMaxY;
 47 
 48     private int mCurrX;
 49     private int mCurrY;
 50     private long mStartTime;
 51     private int mDuration;
 52     private float mDurationReciprocal;
 53     private float mDeltaX;
 54     private float mDeltaY;
 55     private boolean mFinished;
 56     private Interpolator mInterpolator;
 57     private boolean mFlywheel;
 58 
 59     private float mVelocity;
 60 
 61     private static final int DEFAULT_DURATION = 250;
 62     private static final int SCROLL_MODE = 0;
 63     private static final int FLING_MODE = 1;
 64 
 65     private static float DECELERATION_RATE = (float) (Math.log(0.75) / Math.log(0.9));
 66     private static float ALPHA = 800; // pixels / seconds
 67     private static float START_TENSION = 0.4f; // Tension at start: (0.4 * total T, 1.0 * Distance)
 68     private static float END_TENSION = 1.0f - START_TENSION;
 69     private static final int NB_SAMPLES = 100;
 70     private static final float[] SPLINE = new float[NB_SAMPLES + 1];
 71 
 72     private float mDeceleration;
 73     private final float mPpi;
 74 
 75     static {
 76         float x_min = 0.0f;
 77         for (int i = 0; i <= NB_SAMPLES; i++) {
 78             final float t = (float) i / NB_SAMPLES;
 79             float x_max = 1.0f;
 80             float x, tx, coef;
 81             while (true) {
 82                 x = x_min + (x_max - x_min) / 2.0f;
 83                 coef = 3.0f * x * (1.0f - x);
 84                 tx = coef * ((1.0f - x) * START_TENSION + x * END_TENSION) + x * x * x;
 85                 if (Math.abs(tx - t) < 1E-5) break;
 86                 if (tx > t) x_max = x;
 87                 else x_min = x;
 88             }
 89             final float d = coef + x * x * x;
 90             SPLINE[i] = d;
 91         }
 92         SPLINE[NB_SAMPLES] = 1.0f;
 93 
 94         // This controls the viscous fluid effect (how much of it)
 95         sViscousFluidScale = 8.0f;
 96         // must be set to 1.0 (used in viscousFluid())
 97         sViscousFluidNormalize = 1.0f;
 98         sViscousFluidNormalize = 1.0f / viscousFluid(1.0f);
 99     }
100 
101     private static float sViscousFluidScale;
102     private static float sViscousFluidNormalize;
103 
104     /**
105      * Create a Scroller with the default duration and interpolator.
106      */
107     public Scroller(Context context) {
108         this(context, null);
109     }
110 
111     /**
112      * Create a Scroller with the specified interpolator. If the interpolator is
113      * null, the default (viscous) interpolator will be used. "Flywheel" behavior will
114      * be in effect for apps targeting Honeycomb or newer.
115      */
116     public Scroller(Context context, Interpolator interpolator) {
117         this(context, interpolator,
118                 context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB);
119     }
120 
121     /**
122      * Create a Scroller with the specified interpolator. If the interpolator is
123      * null, the default (viscous) interpolator will be used. Specify whether or
124      * not to support progressive "flywheel" behavior in flinging.
125      */
126     public Scroller(Context context, Interpolator interpolator, boolean flywheel) {
127         mFinished = true;
128         mInterpolator = interpolator;
129         mPpi = context.getResources().getDisplayMetrics().density * 160.0f;
130         mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction());
131         mFlywheel = flywheel;
132     }
133 
134     /**
135      * The amount of friction applied to flings. The default value
136      * is {@link ViewConfiguration#getScrollFriction}.
137      * 
138      * @param friction A scalar dimension-less value representing the coefficient of
139      *         friction.
140      */
141     public final void setFriction(float friction) {
142         mDeceleration = computeDeceleration(friction);
143     }
144     
145     private float computeDeceleration(float friction) {
146         return SensorManager.GRAVITY_EARTH   // g (m/s^2)
147                       * 39.37f               // inch/meter
148                       * mPpi                 // pixels per inch
149                       * friction;
150     }
151 
152     /**
153      * 
154      * Returns whether the scroller has finished scrolling.
155      * 
156      * @return True if the scroller has finished scrolling, false otherwise.
157      */
158     public final boolean isFinished() {
159         return mFinished;
160     }
161     
162     /**
163      * Force the finished field to a particular value.
164      *  
165      * @param finished The new finished value.
166      */
167     public final void forceFinished(boolean finished) {
168         mFinished = finished;
169     }
170     
171     /**
172      * Returns how long the scroll event will take, in milliseconds.
173      * 
174      * @return The duration of the scroll in milliseconds.
175      */
176     public final int getDuration() {
177         return mDuration;
178     }
179     
180     /**
181      * Returns the current X offset in the scroll. 
182      * 
183      * @return The new X offset as an absolute distance from the origin.
184      */
185     public final int getCurrX() {
186         return mCurrX;
187     }
188     
189     /**
190      * Returns the current Y offset in the scroll. 
191      * 
192      * @return The new Y offset as an absolute distance from the origin.
193      */
194     public final int getCurrY() {
195         return mCurrY;
196     }
197     
198     /**
199      * Returns the current velocity.
200      *
201      * @return The original velocity less the deceleration. Result may be
202      * negative.
203      */
204     public float getCurrVelocity() {
205         return mVelocity - mDeceleration * timePassed() / 2000.0f;
206     }
207 
208     /**
209      * Returns the start X offset in the scroll. 
210      * 
211      * @return The start X offset as an absolute distance from the origin.
212      */
213     public final int getStartX() {
214         return mStartX;
215     }
216     
217     /**
218      * Returns the start Y offset in the scroll. 
219      * 
220      * @return The start Y offset as an absolute distance from the origin.
221      */
222     public final int getStartY() {
223         return mStartY;
224     }
225     
226     /**
227      * Returns where the scroll will end. Valid only for "fling" scrolls.
228      * 
229      * @return The final X offset as an absolute distance from the origin.
230      */
231     public final int getFinalX() {
232         return mFinalX;
233     }
234     
235     /**
236      * Returns where the scroll will end. Valid only for "fling" scrolls.
237      * 
238      * @return The final Y offset as an absolute distance from the origin.
239      */
240     public final int getFinalY() {
241         return mFinalY;
242     }
243 
244     /**
245      * Call this when you want to know the new location.  If it returns true,
246      * the animation is not yet finished.  loc will be altered to provide the
247      * new location.
248      */ 
249     public boolean computeScrollOffset() {
250         if (mFinished) {
251             return false;
252         }
253 
254         int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
255     
256         if (timePassed < mDuration) {
257             switch (mMode) {
258             case SCROLL_MODE:
259                 float x = timePassed * mDurationReciprocal;
260     
261                 if (mInterpolator == null)
262                     x = viscousFluid(x); 
263                 else
264                     x = mInterpolator.getInterpolation(x);
265     
266                 mCurrX = mStartX + Math.round(x * mDeltaX);
267                 mCurrY = mStartY + Math.round(x * mDeltaY);
268                 break;
269             case FLING_MODE:
270                 final float t = (float) timePassed / mDuration;
271                 final int index = (int) (NB_SAMPLES * t);
272                 final float t_inf = (float) index / NB_SAMPLES;
273                 final float t_sup = (float) (index + 1) / NB_SAMPLES;
274                 final float d_inf = SPLINE[index];
275                 final float d_sup = SPLINE[index + 1];
276                 final float distanceCoef = d_inf + (t - t_inf) / (t_sup - t_inf) * (d_sup - d_inf);
277                 
278                 mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));
279                 // Pin to mMinX <= mCurrX <= mMaxX
280                 mCurrX = Math.min(mCurrX, mMaxX);
281                 mCurrX = Math.max(mCurrX, mMinX);
282                 
283                 mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
284                 // Pin to mMinY <= mCurrY <= mMaxY
285                 mCurrY = Math.min(mCurrY, mMaxY);
286                 mCurrY = Math.max(mCurrY, mMinY);
287 
288                 if (mCurrX == mFinalX && mCurrY == mFinalY) {
289                     mFinished = true;
290                 }
291 
292                 break;
293             }
294         }
295         else {
296             mCurrX = mFinalX;
297             mCurrY = mFinalY;
298             mFinished = true;
299         }
300         return true;
301     }
302     
303     /**
304      * Start scrolling by providing a starting point and the distance to travel.
305      * The scroll will use the default value of 250 milliseconds for the
306      * duration.
307      * 
308      * @param startX Starting horizontal scroll offset in pixels. Positive
309      *        numbers will scroll the content to the left.
310      * @param startY Starting vertical scroll offset in pixels. Positive numbers
311      *        will scroll the content up.
312      * @param dx Horizontal distance to travel. Positive numbers will scroll the
313      *        content to the left.
314      * @param dy Vertical distance to travel. Positive numbers will scroll the
315      *        content up.
316      */
317     public void startScroll(int startX, int startY, int dx, int dy) {
318         startScroll(startX, startY, dx, dy, DEFAULT_DURATION);
319     }
320 
321     /**
322      * Start scrolling by providing a starting point and the distance to travel.
323      * 
324      * @param startX Starting horizontal scroll offset in pixels. Positive
325      *        numbers will scroll the content to the left.
326      * @param startY Starting vertical scroll offset in pixels. Positive numbers
327      *        will scroll the content up.
328      * @param dx Horizontal distance to travel. Positive numbers will scroll the
329      *        content to the left.
330      * @param dy Vertical distance to travel. Positive numbers will scroll the
331      *        content up.
332      * @param duration Duration of the scroll in milliseconds.
333      */
334     public void startScroll(int startX, int startY, int dx, int dy, int duration) {
335         mMode = SCROLL_MODE;
336         mFinished = false;
337         mDuration = duration;
338         mStartTime = AnimationUtils.currentAnimationTimeMillis();
339         mStartX = startX;
340         mStartY = startY;
341         mFinalX = startX + dx;
342         mFinalY = startY + dy;
343         mDeltaX = dx;
344         mDeltaY = dy;
345         mDurationReciprocal = 1.0f / (float) mDuration;
346     }
347 
348     /**
349      * Start scrolling based on a fling gesture. The distance travelled will
350      * depend on the initial velocity of the fling.
351      * 
352      * @param startX Starting point of the scroll (X)
353      * @param startY Starting point of the scroll (Y)
354      * @param velocityX Initial velocity of the fling (X) measured in pixels per
355      *        second.
356      * @param velocityY Initial velocity of the fling (Y) measured in pixels per
357      *        second
358      * @param minX Minimum X value. The scroller will not scroll past this
359      *        point.
360      * @param maxX Maximum X value. The scroller will not scroll past this
361      *        point.
362      * @param minY Minimum Y value. The scroller will not scroll past this
363      *        point.
364      * @param maxY Maximum Y value. The scroller will not scroll past this
365      *        point.
366      */
367     public void fling(int startX, int startY, int velocityX, int velocityY,
368             int minX, int maxX, int minY, int maxY) {
369         // Continue a scroll or fling in progress
370         if (mFlywheel && !mFinished) {
371             float oldVel = getCurrVelocity();
372 
373             float dx = (float) (mFinalX - mStartX);
374             float dy = (float) (mFinalY - mStartY);
375             float hyp = FloatMath.sqrt(dx * dx + dy * dy);
376 
377             float ndx = dx / hyp;
378             float ndy = dy / hyp;
379 
380             float oldVelocityX = ndx * oldVel;
381             float oldVelocityY = ndy * oldVel;
382             if (Math.signum(velocityX) == Math.signum(oldVelocityX) &&
383                     Math.signum(velocityY) == Math.signum(oldVelocityY)) {
384                 velocityX += oldVelocityX;
385                 velocityY += oldVelocityY;
386             }
387         }
388 
389         mMode = FLING_MODE;
390         mFinished = false;
391 
392         float velocity = FloatMath.sqrt(velocityX * velocityX + velocityY * velocityY);
393      
394         mVelocity = velocity;
395         final double l = Math.log(START_TENSION * velocity / ALPHA);
396         mDuration = (int) (1000.0 * Math.exp(l / (DECELERATION_RATE - 1.0)));
397         mStartTime = AnimationUtils.currentAnimationTimeMillis();
398         mStartX = startX;
399         mStartY = startY;
400 
401         float coeffX = velocity == 0 ? 1.0f : velocityX / velocity;
402         float coeffY = velocity == 0 ? 1.0f : velocityY / velocity;
403 
404         int totalDistance =
405                 (int) (ALPHA * Math.exp(DECELERATION_RATE / (DECELERATION_RATE - 1.0) * l));
406         
407         mMinX = minX;
408         mMaxX = maxX;
409         mMinY = minY;
410         mMaxY = maxY;
411 
412         mFinalX = startX + Math.round(totalDistance * coeffX);
413         // Pin to mMinX <= mFinalX <= mMaxX
414         mFinalX = Math.min(mFinalX, mMaxX);
415         mFinalX = Math.max(mFinalX, mMinX);
416         
417         mFinalY = startY + Math.round(totalDistance * coeffY);
418         // Pin to mMinY <= mFinalY <= mMaxY
419         mFinalY = Math.min(mFinalY, mMaxY);
420         mFinalY = Math.max(mFinalY, mMinY);
421     }
422     
423     static float viscousFluid(float x)
424     {
425         x *= sViscousFluidScale;
426         if (x < 1.0f) {
427             x -= (1.0f - (float)Math.exp(-x));
428         } else {
429             float start = 0.36787944117f;   // 1/e == exp(-1)
430             x = 1.0f - (float)Math.exp(1.0f - x);
431             x = start + x * (1.0f - start);
432         }
433         x *= sViscousFluidNormalize;
434         return x;
435     }
436     
437     /**
438      * Stops the animation. Contrary to {@link #forceFinished(boolean)},
439      * aborting the animating cause the scroller to move to the final x and y
440      * position
441      *
442      * @see #forceFinished(boolean)
443      */
444     public void abortAnimation() {
445         mCurrX = mFinalX;
446         mCurrY = mFinalY;
447         mFinished = true;
448     }
449     
450     /**
451      * Extend the scroll animation. This allows a running animation to scroll
452      * further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}.
453      *
454      * @param extend Additional time to scroll in milliseconds.
455      * @see #setFinalX(int)
456      * @see #setFinalY(int)
457      */
458     public void extendDuration(int extend) {
459         int passed = timePassed();
460         mDuration = passed + extend;
461         mDurationReciprocal = 1.0f / mDuration;
462         mFinished = false;
463     }
464 
465     /**
466      * Returns the time elapsed since the beginning of the scrolling.
467      *
468      * @return The elapsed time in milliseconds.
469      */
470     public int timePassed() {
471         return (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
472     }
473 
474     /**
475      * Sets the final position (X) for this scroller.
476      *
477      * @param newX The new X offset as an absolute distance from the origin.
478      * @see #extendDuration(int)
479      * @see #setFinalY(int)
480      */
481     public void setFinalX(int newX) {
482         mFinalX = newX;
483         mDeltaX = mFinalX - mStartX;
484         mFinished = false;
485     }
486 
487     /**
488      * Sets the final position (Y) for this scroller.
489      *
490      * @param newY The new Y offset as an absolute distance from the origin.
491      * @see #extendDuration(int)
492      * @see #setFinalX(int)
493      */
494     public void setFinalY(int newY) {
495         mFinalY = newY;
496         mDeltaY = mFinalY - mStartY;
497         mFinished = false;
498     }
499 
500     /**
501      * @hide
502      */
503     public boolean isScrollingInDirection(float xvel, float yvel) {
504         return !mFinished && Math.signum(xvel) == Math.signum(mFinalX - mStartX) &&
505                 Math.signum(yvel) == Math.signum(mFinalY - mStartY);
506     }
507 }

Scroller源码只有507行,结合链接中资料发现,Scroller只是一个计算滚动位置的帮助类,用来计算出当前应该滚动到的位置,而且每次获取位置必须调用computeScrollOffset方法才能刷新,Scroller还是很好用的,按照这个思路,以后如果滑动需要特殊计算可以按照Scroller自定义一个计算类。

原文地址:https://www.cnblogs.com/afluy/p/4556380.html