FlingScroller.java revision b3aab90bb37aa9cc60be32e05678ee55d6575ee8
1/*
2 * Copyright (C) 2011 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
17package com.android.gallery3d.ui;
18
19import com.android.gallery3d.common.Utils;
20
21// This is a customized version of Scroller, with a interface similar to
22// android.widget.Scroller. It does fling only, not scroll.
23//
24// The differences between the this Scroller and the system one are:
25//
26// (1) The velocity does not change because of min/max limit.
27// (2) The duration is different.
28// (3) The deceleration curve is different.
29class FlingScroller {
30    private static final String TAG = "FlingController";
31
32    // The fling duration (in milliseconds) when velocity is 1 pixel/second
33    private static final float FLING_DURATION_PARAM = 50f;
34    private static final int DECELERATED_FACTOR = 4;
35
36    private int mStartX, mStartY;
37    private int mMinX, mMinY, mMaxX, mMaxY;
38    private double mSinAngle;
39    private double mCosAngle;
40    private int mDuration;
41    private int mDistance;
42    private int mFinalX, mFinalY;
43
44    private int mCurrX, mCurrY;
45
46    public int getFinalX() {
47        return mFinalX;
48    }
49
50    public int getFinalY() {
51        return mFinalY;
52    }
53
54    public int getDuration() {
55        return mDuration;
56    }
57
58    public int getCurrX() {
59        return mCurrX;
60
61    }
62
63    public int getCurrY() {
64        return mCurrY;
65    }
66
67    public void fling(int startX, int startY, int velocityX, int velocityY,
68            int minX, int maxX, int minY, int maxY) {
69        mStartX = startX;
70        mStartY = startY;
71        mMinX = minX;
72        mMinY = minY;
73        mMaxX = maxX;
74        mMaxY = maxY;
75
76        double velocity = Math.hypot(velocityX, velocityY);
77        mSinAngle = velocityY / velocity;
78        mCosAngle = velocityX / velocity;
79        //
80        // The position formula: x(t) = s + (e - s) * (1 - (1 - t / T) ^ d)
81        //     velocity formula: v(t) = d * (e - s) * (1 - t / T) ^ (d - 1) / T
82        // Thus,
83        //     v0 = d * (e - s) / T => (e - s) = v0 * T / d
84        //
85
86        // Ta = T_ref * (Va / V_ref) ^ (1 / (d - 1)); V_ref = 1 pixel/second;
87        mDuration = (int)Math.round(FLING_DURATION_PARAM
88                * Math.pow(Math.abs(velocity), 1.0 / (DECELERATED_FACTOR - 1)));
89
90        // (e - s) = v0 * T / d
91        mDistance = (int)Math.round(
92                velocity * mDuration / DECELERATED_FACTOR / 1000);
93
94        mFinalX = getX(1.0f);
95        mFinalY = getY(1.0f);
96    }
97
98    public void computeScrollOffset(float progress) {
99        progress = Math.min(progress, 1);
100        float f = 1 - progress;
101        f = 1 - (float) Math.pow(f, DECELERATED_FACTOR);
102        mCurrX = getX(f);
103        mCurrY = getY(f);
104    }
105
106    private int getX(float f) {
107        return (int) Utils.clamp(
108                Math.round(mStartX + f * mDistance * mCosAngle), mMinX, mMaxX);
109    }
110
111    private int getY(float f) {
112        return (int) Utils.clamp(
113                Math.round(mStartY + f * mDistance * mSinAngle), mMinY, mMaxY);
114    }
115}
116