资料: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 is113      * null, the default (viscous) interpolator will be used. "Flywheel" behavior will114      * 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 is123      * null, the default (viscous) interpolator will be used. Specify whether or124      * 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 value136      * is {@link ViewConfiguration#getScrollFriction}.137      * 138      * @param friction A scalar dimension-less value representing the coefficient of139      *         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/meter148                       * mPpi                 // pixels per inch149                       * 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 be202      * 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 the247      * 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                 else264                     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 <= mMaxX280                 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 <= mMaxY285                 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 the306      * duration.307      * 308      * @param startX Starting horizontal scroll offset in pixels. Positive309      *        numbers will scroll the content to the left.310      * @param startY Starting vertical scroll offset in pixels. Positive numbers311      *        will scroll the content up.312      * @param dx Horizontal distance to travel. Positive numbers will scroll the313      *        content to the left.314      * @param dy Vertical distance to travel. Positive numbers will scroll the315      *        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. Positive325      *        numbers will scroll the content to the left.326      * @param startY Starting vertical scroll offset in pixels. Positive numbers327      *        will scroll the content up.328      * @param dx Horizontal distance to travel. Positive numbers will scroll the329      *        content to the left.330      * @param dy Vertical distance to travel. Positive numbers will scroll the331      *        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 will350      * 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 per355      *        second.356      * @param velocityY Initial velocity of the fling (Y) measured in pixels per357      *        second358      * @param minX Minimum X value. The scroller will not scroll past this359      *        point.360      * @param maxX Maximum X value. The scroller will not scroll past this361      *        point.362      * @param minY Minimum Y value. The scroller will not scroll past this363      *        point.364      * @param maxY Maximum Y value. The scroller will not scroll past this365      *        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 progress370         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 <= mMaxX414         mFinalX = Math.min(mFinalX, mMaxX);415         mFinalX = Math.max(mFinalX, mMinX);416         417         mFinalY = startY + Math.round(totalDistance * coeffY);418         // Pin to mMinY <= mFinalY <= mMaxY419         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 y440      * position441      *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 scroll452      * 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      * @hide502      */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自定义一个计算类。

更多相关文章

  1. Android调用系统相机拍照并保存到指定位置
  2. android上,实现直接在屏幕上显示点击位置,方便调试。
  3. 分享Android入门学习资料
  4. ANDROID PAD版本 PHONE版本 源码有什么 区别?
  5. android学习资料链接汇总
  6. 改变Android 对话框位置及边框
  7. Android图片浏览之源码
  8. Android 7.0 移除设置中的某些项(辅助功能、流量使用情况、位置信

随机推荐

  1. android中全局变量的运用
  2. [原]如何在Android用FFmpeg解码图像
  3. No 90 · android如何调用dotnet编写的we
  4. AndroidHttpClient使用Cookie应用分析
  5. Android中的Intent和Intent-Filter详解(一
  6. EditText的inputType属性详解,让指定的Edi
  7. Android(安卓)API 解析开发包
  8. Android中AsyncTask的简单用法
  9. Android(安卓)StagefrightPlayer
  10. android 引用类库工程编译时报错