diff options
Diffstat (limited to 'src/com/android/gallery3d/ui/FlingScroller.java')
-rw-r--r-- | src/com/android/gallery3d/ui/FlingScroller.java | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/ui/FlingScroller.java b/src/com/android/gallery3d/ui/FlingScroller.java new file mode 100644 index 000000000..6f98c64f9 --- /dev/null +++ b/src/com/android/gallery3d/ui/FlingScroller.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.gallery3d.ui; + + +// This is a customized version of Scroller, with a interface similar to +// android.widget.Scroller. It does fling only, not scroll. +// +// The differences between the this Scroller and the system one are: +// +// (1) The velocity does not change because of min/max limit. +// (2) The duration is different. +// (3) The deceleration curve is different. +class FlingScroller { + @SuppressWarnings("unused") + private static final String TAG = "FlingController"; + + // The fling duration (in milliseconds) when velocity is 1 pixel/second + private static final float FLING_DURATION_PARAM = 50f; + private static final int DECELERATED_FACTOR = 4; + + private int mStartX, mStartY; + private int mMinX, mMinY, mMaxX, mMaxY; + private double mSinAngle; + private double mCosAngle; + private int mDuration; + private int mDistance; + private int mFinalX, mFinalY; + + private int mCurrX, mCurrY; + private double mCurrV; + + public int getFinalX() { + return mFinalX; + } + + public int getFinalY() { + return mFinalY; + } + + public int getDuration() { + return mDuration; + } + + public int getCurrX() { + return mCurrX; + + } + + public int getCurrY() { + return mCurrY; + } + + public int getCurrVelocityX() { + return (int)Math.round(mCurrV * mCosAngle); + } + + public int getCurrVelocityY() { + return (int)Math.round(mCurrV * mSinAngle); + } + + public void fling(int startX, int startY, int velocityX, int velocityY, + int minX, int maxX, int minY, int maxY) { + mStartX = startX; + mStartY = startY; + mMinX = minX; + mMinY = minY; + mMaxX = maxX; + mMaxY = maxY; + + double velocity = Math.hypot(velocityX, velocityY); + mSinAngle = velocityY / velocity; + mCosAngle = velocityX / velocity; + // + // The position formula: x(t) = s + (e - s) * (1 - (1 - t / T) ^ d) + // velocity formula: v(t) = d * (e - s) * (1 - t / T) ^ (d - 1) / T + // Thus, + // v0 = d * (e - s) / T => (e - s) = v0 * T / d + // + + // Ta = T_ref * (Va / V_ref) ^ (1 / (d - 1)); V_ref = 1 pixel/second; + mDuration = (int)Math.round(FLING_DURATION_PARAM + * Math.pow(Math.abs(velocity), 1.0 / (DECELERATED_FACTOR - 1))); + + // (e - s) = v0 * T / d + mDistance = (int)Math.round( + velocity * mDuration / DECELERATED_FACTOR / 1000); + + mFinalX = getX(1.0f); + mFinalY = getY(1.0f); + } + + public void computeScrollOffset(float progress) { + progress = Math.min(progress, 1); + float f = 1 - progress; + f = 1 - (float) Math.pow(f, DECELERATED_FACTOR); + mCurrX = getX(f); + mCurrY = getY(f); + mCurrV = getV(progress); + } + + private int getX(float f) { + int r = (int) Math.round(mStartX + f * mDistance * mCosAngle); + if (mCosAngle > 0 && mStartX <= mMaxX) { + r = Math.min(r, mMaxX); + } else if (mCosAngle < 0 && mStartX >= mMinX) { + r = Math.max(r, mMinX); + } + return r; + } + + private int getY(float f) { + int r = (int) Math.round(mStartY + f * mDistance * mSinAngle); + if (mSinAngle > 0 && mStartY <= mMaxY) { + r = Math.min(r, mMaxY); + } else if (mSinAngle < 0 && mStartY >= mMinY) { + r = Math.max(r, mMinY); + } + return r; + } + + private double getV(float progress) { + // velocity formula: v(t) = d * (e - s) * (1 - t / T) ^ (d - 1) / T + return DECELERATED_FACTOR * mDistance * 1000 * + Math.pow(1 - progress, DECELERATED_FACTOR - 1) / mDuration; + } +} |