19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.widget; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 20c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottierimport android.hardware.SensorManager; 21d348bb4feff72d047a1037537be2d334a00c380cGilles Debunneimport android.os.Build; 22d348bb4feff72d047a1037537be2d334a00c380cGilles Debunneimport android.util.FloatMath; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewConfiguration; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.animation.AnimationUtils; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.animation.Interpolator; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This class encapsulates scrolling. The duration of the scroll 309d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * can be passed in the constructor and specifies the maximum time that 319d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * the scrolling animation should take. Past this time, the scrolling is 329d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * automatically moved to its final stage and computeScrollOffset() 339d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * will always return false to indicate that scrolling is over. 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class Scroller { 366579b0b4ac0e781efab044aaaf3f66447cf5e067Adam Powell private int mMode; 3752964243dc95f74ac2ab9a96d031a36931a11931Gilles Debunne 389d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell private int mStartX; 399d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell private int mStartY; 409d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell private int mFinalX; 419d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell private int mFinalY; 429d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 439d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell private int mMinX; 449d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell private int mMaxX; 459d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell private int mMinY; 469d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell private int mMaxY; 479d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 489d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell private int mCurrX; 499d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell private int mCurrY; 509d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell private long mStartTime; 519d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell private int mDuration; 529d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell private float mDurationReciprocal; 539d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell private float mDeltaX; 549d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell private float mDeltaY; 559d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell private boolean mFinished; 569d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell private Interpolator mInterpolator; 57d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne private boolean mFlywheel; 589d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 599d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell private float mVelocity; 60990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell private float mCurrVelocity; 61990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell private int mDistance; 62990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell 63990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell private float mFlingFriction = ViewConfiguration.getScrollFriction(); 6452964243dc95f74ac2ab9a96d031a36931a11931Gilles Debunne 656579b0b4ac0e781efab044aaaf3f66447cf5e067Adam Powell private static final int DEFAULT_DURATION = 250; 666579b0b4ac0e781efab044aaaf3f66447cf5e067Adam Powell private static final int SCROLL_MODE = 0; 676579b0b4ac0e781efab044aaaf3f66447cf5e067Adam Powell private static final int FLING_MODE = 1; 6852964243dc95f74ac2ab9a96d031a36931a11931Gilles Debunne 69990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell private static float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9)); 70990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1) 71990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell private static final float START_TENSION = 0.5f; 72990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell private static final float END_TENSION = 1.0f; 73990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell private static final float P1 = START_TENSION * INFLEXION; 74990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell private static final float P2 = 1.0f - END_TENSION * (1.0f - INFLEXION); 75990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell 76d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne private static final int NB_SAMPLES = 100; 77990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell private static final float[] SPLINE_POSITION = new float[NB_SAMPLES + 1]; 78990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell private static final float[] SPLINE_TIME = new float[NB_SAMPLES + 1]; 79d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne 804bede9e425875542976a422222510fa4056a8339Romain Guy private float mDeceleration; 814bede9e425875542976a422222510fa4056a8339Romain Guy private final float mPpi; 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 83990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell // A context-specific coefficient adjusted to physical values. 84990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell private float mPhysicalCoeff; 85990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell 86d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne static { 87d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne float x_min = 0.0f; 88990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell float y_min = 0.0f; 89990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell for (int i = 0; i < NB_SAMPLES; i++) { 90990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell final float alpha = (float) i / NB_SAMPLES; 91990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell 92d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne float x_max = 1.0f; 93d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne float x, tx, coef; 94d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne while (true) { 95d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne x = x_min + (x_max - x_min) / 2.0f; 96d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne coef = 3.0f * x * (1.0f - x); 97990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell tx = coef * ((1.0f - x) * P1 + x * P2) + x * x * x; 98990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell if (Math.abs(tx - alpha) < 1E-5) break; 99990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell if (tx > alpha) x_max = x; 100d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne else x_min = x; 101d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne } 102990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell SPLINE_POSITION[i] = coef * ((1.0f - x) * START_TENSION + x) + x * x * x; 103990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell 104990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell float y_max = 1.0f; 105990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell float y, dy; 106990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell while (true) { 107990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell y = y_min + (y_max - y_min) / 2.0f; 108990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell coef = 3.0f * y * (1.0f - y); 109990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell dy = coef * ((1.0f - y) * START_TENSION + y) + y * y * y; 110990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell if (Math.abs(dy - alpha) < 1E-5) break; 111990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell if (dy > alpha) y_max = y; 112990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell else y_min = y; 113990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell } 114990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell SPLINE_TIME[i] = coef * ((1.0f - y) * P1 + y * P2) + y * y * y; 115d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne } 116990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell SPLINE_POSITION[NB_SAMPLES] = SPLINE_TIME[NB_SAMPLES] = 1.0f; 117637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 118637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // This controls the viscous fluid effect (how much of it) 119637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell sViscousFluidScale = 8.0f; 120637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell // must be set to 1.0 (used in viscousFluid()) 121637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell sViscousFluidNormalize = 1.0f; 122637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell sViscousFluidNormalize = 1.0f / viscousFluid(1.0f); 123990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell 124d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne } 125d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne 126637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private static float sViscousFluidScale; 127637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell private static float sViscousFluidNormalize; 128637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1309d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * Create a Scroller with the default duration and interpolator. 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Scroller(Context context) { 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this(context, null); 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 136637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell /** 137637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * Create a Scroller with the specified interpolator. If the interpolator is 138637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * null, the default (viscous) interpolator will be used. "Flywheel" behavior will 139637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * be in effect for apps targeting Honeycomb or newer. 140637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell */ 141d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne public Scroller(Context context, Interpolator interpolator) { 142d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne this(context, interpolator, 143d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB); 144d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne } 145d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Create a Scroller with the specified interpolator. If the interpolator is 148637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * null, the default (viscous) interpolator will be used. Specify whether or 149637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell * not to support progressive "flywheel" behavior in flinging. 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 151d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne public Scroller(Context context, Interpolator interpolator, boolean flywheel) { 1529d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mFinished = true; 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mInterpolator = interpolator; 1544bede9e425875542976a422222510fa4056a8339Romain Guy mPpi = context.getResources().getDisplayMetrics().density * 160.0f; 1554bede9e425875542976a422222510fa4056a8339Romain Guy mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction()); 156d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne mFlywheel = flywheel; 157990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell 158990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell mPhysicalCoeff = computeDeceleration(0.84f); // look and feel tuning 1594bede9e425875542976a422222510fa4056a8339Romain Guy } 1604bede9e425875542976a422222510fa4056a8339Romain Guy 1614bede9e425875542976a422222510fa4056a8339Romain Guy /** 1624bede9e425875542976a422222510fa4056a8339Romain Guy * The amount of friction applied to flings. The default value 1634bede9e425875542976a422222510fa4056a8339Romain Guy * is {@link ViewConfiguration#getScrollFriction}. 1644bede9e425875542976a422222510fa4056a8339Romain Guy * 165d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne * @param friction A scalar dimension-less value representing the coefficient of 1664bede9e425875542976a422222510fa4056a8339Romain Guy * friction. 1674bede9e425875542976a422222510fa4056a8339Romain Guy */ 1684bede9e425875542976a422222510fa4056a8339Romain Guy public final void setFriction(float friction) { 169a655c635820425a4c98314c3ba02eb382229b45dRomain Guy mDeceleration = computeDeceleration(friction); 170990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell mFlingFriction = friction; 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1729d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 1734bede9e425875542976a422222510fa4056a8339Romain Guy private float computeDeceleration(float friction) { 1744bede9e425875542976a422222510fa4056a8339Romain Guy return SensorManager.GRAVITY_EARTH // g (m/s^2) 1754bede9e425875542976a422222510fa4056a8339Romain Guy * 39.37f // inch/meter 1764bede9e425875542976a422222510fa4056a8339Romain Guy * mPpi // pixels per inch 1774bede9e425875542976a422222510fa4056a8339Romain Guy * friction; 1784bede9e425875542976a422222510fa4056a8339Romain Guy } 1794bede9e425875542976a422222510fa4056a8339Romain Guy 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns whether the scroller has finished scrolling. 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return True if the scroller has finished scrolling, false otherwise. 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final boolean isFinished() { 1879d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell return mFinished; 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1899d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Force the finished field to a particular value. 1929d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param finished The new finished value. 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final void forceFinished(boolean finished) { 1969d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mFinished = finished; 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1989d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns how long the scroll event will take, in milliseconds. 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The duration of the scroll in milliseconds. 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getDuration() { 2059d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell return mDuration; 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2079d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2099d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * Returns the current X offset in the scroll. 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The new X offset as an absolute distance from the origin. 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getCurrX() { 2149d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell return mCurrX; 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2169d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2189d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * Returns the current Y offset in the scroll. 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The new Y offset as an absolute distance from the origin. 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getCurrY() { 2239d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell return mCurrY; 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2259d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 227278ce05b52a47a09d2177435b533f4ecb1b9c4daCary Clark * Returns the current velocity. 2289d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * 2299d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * @return The original velocity less the deceleration. Result may be 2309d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * negative. 231278ce05b52a47a09d2177435b533f4ecb1b9c4daCary Clark */ 232278ce05b52a47a09d2177435b533f4ecb1b9c4daCary Clark public float getCurrVelocity() { 233990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell return mMode == FLING_MODE ? 234990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell mCurrVelocity : mVelocity - mDeceleration * timePassed() / 2000.0f; 235278ce05b52a47a09d2177435b533f4ecb1b9c4daCary Clark } 236278ce05b52a47a09d2177435b533f4ecb1b9c4daCary Clark 237278ce05b52a47a09d2177435b533f4ecb1b9c4daCary Clark /** 2389d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * Returns the start X offset in the scroll. 2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The start X offset as an absolute distance from the origin. 2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getStartX() { 2439d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell return mStartX; 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2459d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2479d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * Returns the start Y offset in the scroll. 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The start Y offset as an absolute distance from the origin. 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getStartY() { 2529d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell return mStartY; 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2549d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns where the scroll will end. Valid only for "fling" scrolls. 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The final X offset as an absolute distance from the origin. 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getFinalX() { 2619d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell return mFinalX; 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2639d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Returns where the scroll will end. Valid only for "fling" scrolls. 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return The final Y offset as an absolute distance from the origin. 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int getFinalY() { 2709d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell return mFinalY; 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2749d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * Call this when you want to know the new location. If it returns true, 2759d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * the animation is not yet finished. loc will be altered to provide the 2769d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * new location. 2779d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell */ 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean computeScrollOffset() { 2799d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell if (mFinished) { 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2839d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); 2849d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 2859d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell if (timePassed < mDuration) { 2869d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell switch (mMode) { 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case SCROLL_MODE: 288d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne float x = timePassed * mDurationReciprocal; 2899d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 2909d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell if (mInterpolator == null) 2919d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell x = viscousFluid(x); 2929d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell else 2939d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell x = mInterpolator.getInterpolation(x); 2949d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 2959d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mCurrX = mStartX + Math.round(x * mDeltaX); 2969d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mCurrY = mStartY + Math.round(x * mDeltaY); 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case FLING_MODE: 299d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne final float t = (float) timePassed / mDuration; 300d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne final int index = (int) (NB_SAMPLES * t); 301990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell float distanceCoef = 1.f; 302990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell float velocityCoef = 0.f; 303990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell if (index < NB_SAMPLES) { 304990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell final float t_inf = (float) index / NB_SAMPLES; 305990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell final float t_sup = (float) (index + 1) / NB_SAMPLES; 306990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell final float d_inf = SPLINE_POSITION[index]; 307990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell final float d_sup = SPLINE_POSITION[index + 1]; 308990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell velocityCoef = (d_sup - d_inf) / (t_sup - t_inf); 309990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell distanceCoef = d_inf + (t - t_inf) * velocityCoef; 310990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell } 311990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell 312990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f; 3139d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 314d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX)); 3159d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell // Pin to mMinX <= mCurrX <= mMaxX 3169d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mCurrX = Math.min(mCurrX, mMaxX); 3179d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mCurrX = Math.max(mCurrX, mMinX); 3189d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 319d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY)); 3209d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell // Pin to mMinY <= mCurrY <= mMaxY 3219d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mCurrY = Math.min(mCurrY, mMaxY); 3229d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mCurrY = Math.max(mCurrY, mMinY); 3231b088be8bb304e4ab7a1896d3ec3b9df9d9cf68eAdam Powell 3241b088be8bb304e4ab7a1896d3ec3b9df9d9cf68eAdam Powell if (mCurrX == mFinalX && mCurrY == mFinalY) { 3251b088be8bb304e4ab7a1896d3ec3b9df9d9cf68eAdam Powell mFinished = true; 3261b088be8bb304e4ab7a1896d3ec3b9df9d9cf68eAdam Powell } 3271b088be8bb304e4ab7a1896d3ec3b9df9d9cf68eAdam Powell 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3299d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell } 3309d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell } 3319d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell else { 3329d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mCurrX = mFinalX; 3339d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mCurrY = mFinalY; 3349d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mFinished = true; 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3389d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Start scrolling by providing a starting point and the distance to travel. 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The scroll will use the default value of 250 milliseconds for the 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * duration. 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param startX Starting horizontal scroll offset in pixels. Positive 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * numbers will scroll the content to the left. 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param startY Starting vertical scroll offset in pixels. Positive numbers 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will scroll the content up. 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param dx Horizontal distance to travel. Positive numbers will scroll the 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * content to the left. 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param dy Vertical distance to travel. Positive numbers will scroll the 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * content up. 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void startScroll(int startX, int startY, int dx, int dy) { 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project startScroll(startX, startY, dx, dy, DEFAULT_DURATION); 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Start scrolling by providing a starting point and the distance to travel. 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param startX Starting horizontal scroll offset in pixels. Positive 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * numbers will scroll the content to the left. 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param startY Starting vertical scroll offset in pixels. Positive numbers 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will scroll the content up. 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param dx Horizontal distance to travel. Positive numbers will scroll the 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * content to the left. 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param dy Vertical distance to travel. Positive numbers will scroll the 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * content up. 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param duration Duration of the scroll in milliseconds. 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void startScroll(int startX, int startY, int dx, int dy, int duration) { 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMode = SCROLL_MODE; 3729d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mFinished = false; 3739d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mDuration = duration; 3749d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mStartTime = AnimationUtils.currentAnimationTimeMillis(); 3759d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mStartX = startX; 3769d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mStartY = startY; 3779d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mFinalX = startX + dx; 3789d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mFinalY = startY + dy; 3799d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mDeltaX = dx; 3809d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mDeltaY = dy; 381637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell mDurationReciprocal = 1.0f / (float) mDuration; 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3859d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * Start scrolling based on a fling gesture. The distance travelled will 3869d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * depend on the initial velocity of the fling. 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param startX Starting point of the scroll (X) 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param startY Starting point of the scroll (Y) 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param velocityX Initial velocity of the fling (X) measured in pixels per 3919d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * second. 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param velocityY Initial velocity of the fling (Y) measured in pixels per 3939d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * second 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param minX Minimum X value. The scroller will not scroll past this 3959d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * point. 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param maxX Maximum X value. The scroller will not scroll past this 3979d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * point. 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param minY Minimum Y value. The scroller will not scroll past this 3999d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * point. 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param maxY Maximum Y value. The scroller will not scroll past this 4019d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * point. 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void fling(int startX, int startY, int velocityX, int velocityY, 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int minX, int maxX, int minY, int maxY) { 405d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne // Continue a scroll or fling in progress 406d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne if (mFlywheel && !mFinished) { 407d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne float oldVel = getCurrVelocity(); 408d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne 409d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne float dx = (float) (mFinalX - mStartX); 410d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne float dy = (float) (mFinalY - mStartY); 411d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne float hyp = FloatMath.sqrt(dx * dx + dy * dy); 412d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne 413d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne float ndx = dx / hyp; 414d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne float ndy = dy / hyp; 415d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne 416d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne float oldVelocityX = ndx * oldVel; 417d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne float oldVelocityY = ndy * oldVel; 418d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne if (Math.signum(velocityX) == Math.signum(oldVelocityX) && 419d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne Math.signum(velocityY) == Math.signum(oldVelocityY)) { 420d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne velocityX += oldVelocityX; 421d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne velocityY += oldVelocityY; 422d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne } 423d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne } 424d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMode = FLING_MODE; 4269d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mFinished = false; 4279d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 428d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne float velocity = FloatMath.sqrt(velocityX * velocityX + velocityY * velocityY); 4299d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 4309d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mVelocity = velocity; 431990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell mDuration = getSplineFlingDuration(velocity); 4329d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mStartTime = AnimationUtils.currentAnimationTimeMillis(); 4339d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mStartX = startX; 4349d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mStartY = startY; 4359d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 436637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell float coeffX = velocity == 0 ? 1.0f : velocityX / velocity; 437637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell float coeffY = velocity == 0 ? 1.0f : velocityY / velocity; 4389d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 439990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell double totalDistance = getSplineFlingDistance(velocity); 440990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell mDistance = (int) (totalDistance * Math.signum(velocity)); 4419d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 4429d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mMinX = minX; 4439d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mMaxX = maxX; 4449d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mMinY = minY; 4459d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mMaxY = maxY; 446d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne 447990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell mFinalX = startX + (int) Math.round(totalDistance * coeffX); 4489d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell // Pin to mMinX <= mFinalX <= mMaxX 4499d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mFinalX = Math.min(mFinalX, mMaxX); 4509d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mFinalX = Math.max(mFinalX, mMinX); 4519d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 452990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell mFinalY = startY + (int) Math.round(totalDistance * coeffY); 4539d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell // Pin to mMinY <= mFinalY <= mMaxY 4549d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mFinalY = Math.min(mFinalY, mMaxY); 4559d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mFinalY = Math.max(mFinalY, mMinY); 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4579d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 458990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell private double getSplineDeceleration(float velocity) { 459990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell return Math.log(INFLEXION * Math.abs(velocity) / (mFlingFriction * mPhysicalCoeff)); 460990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell } 461990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell 462990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell private int getSplineFlingDuration(float velocity) { 463990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell final double l = getSplineDeceleration(velocity); 464990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell final double decelMinusOne = DECELERATION_RATE - 1.0; 465990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell return (int) (1000.0 * Math.exp(l / decelMinusOne)); 466990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell } 467990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell 468990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell private double getSplineFlingDistance(float velocity) { 469990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell final double l = getSplineDeceleration(velocity); 470990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell final double decelMinusOne = DECELERATION_RATE - 1.0; 471990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell return mFlingFriction * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l); 472990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell } 473990dfc6f908c8fc22bb15a3e0a36699e954ec28cAdam Powell 474637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell static float viscousFluid(float x) 4759d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell { 476637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell x *= sViscousFluidScale; 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (x < 1.0f) { 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project x -= (1.0f - (float)Math.exp(-x)); 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float start = 0.36787944117f; // 1/e == exp(-1) 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project x = 1.0f - (float)Math.exp(1.0f - x); 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project x = start + x * (1.0f - start); 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 484637d337b58d8eec6de19230a5dd5ca5581c0478dAdam Powell x *= sViscousFluidNormalize; 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return x; 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4879d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 489c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier * Stops the animation. Contrary to {@link #forceFinished(boolean)}, 490c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier * aborting the animating cause the scroller to move to the final x and y 491c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier * position 4929d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * 493c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier * @see #forceFinished(boolean) 4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void abortAnimation() { 4969d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mCurrX = mFinalX; 4979d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mCurrY = mFinalY; 4989d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mFinished = true; 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5009d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 502c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier * Extend the scroll animation. This allows a running animation to scroll 503d663dab7dbefb49877efd2976994fb94cfa4fbd0djken * further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}. 5049d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param extend Additional time to scroll in milliseconds. 506c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier * @see #setFinalX(int) 507c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier * @see #setFinalY(int) 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void extendDuration(int extend) { 5109d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell int passed = timePassed(); 5119d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mDuration = passed + extend; 512d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne mDurationReciprocal = 1.0f / mDuration; 5139d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mFinished = false; 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 515c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier 516c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier /** 517c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier * Returns the time elapsed since the beginning of the scrolling. 5189d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * 519c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier * @return The elapsed time in milliseconds. 520c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier */ 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int timePassed() { 5229d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell return (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime); 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 524c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier 525c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier /** 526c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier * Sets the final position (X) for this scroller. 5279d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * 528c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier * @param newX The new X offset as an absolute distance from the origin. 529c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier * @see #extendDuration(int) 530c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier * @see #setFinalY(int) 531c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier */ 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setFinalX(int newX) { 5339d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mFinalX = newX; 5349d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mDeltaX = mFinalX - mStartX; 5359d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mFinished = false; 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 538c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier /** 539c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier * Sets the final position (Y) for this scroller. 5409d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell * 541c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier * @param newY The new Y offset as an absolute distance from the origin. 542c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier * @see #extendDuration(int) 543c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier * @see #setFinalX(int) 544c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier */ 545c312942b773449f5c6a8a887052aec847ec73b2cCyril Mottier public void setFinalY(int newY) { 5469d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mFinalY = newY; 5479d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mDeltaY = mFinalY - mStartY; 5489d32d24dbd8a015c9d5c44ed4901d5a666eb8e7fAdam Powell mFinished = false; 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 550d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne 551d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne /** 552d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne * @hide 553d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne */ 554d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne public boolean isScrollingInDirection(float xvel, float yvel) { 555d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne return !mFinished && Math.signum(xvel) == Math.signum(mFinalX - mStartX) && 556d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne Math.signum(yvel) == Math.signum(mFinalY - mStartY); 557d348bb4feff72d047a1037537be2d334a00c380cGilles Debunne } 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 559