diff options
Diffstat (limited to 'src/com/android/gallery3d/ui/Paper.java')
-rw-r--r-- | src/com/android/gallery3d/ui/Paper.java | 146 |
1 files changed, 112 insertions, 34 deletions
diff --git a/src/com/android/gallery3d/ui/Paper.java b/src/com/android/gallery3d/ui/Paper.java index 641fc2c8e..ecc415064 100644 --- a/src/com/android/gallery3d/ui/Paper.java +++ b/src/com/android/gallery3d/ui/Paper.java @@ -16,10 +16,14 @@ package com.android.gallery3d.ui; +import com.android.gallery3d.common.Utils; import com.android.gallery3d.ui.PositionRepository.Position; import com.android.gallery3d.util.GalleryUtils; import android.opengl.Matrix; +import android.os.SystemClock; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.Interpolator; import javax.microedition.khronos.opengles.GL11; import javax.microedition.khronos.opengles.GL11ExtensionPack; @@ -28,22 +32,37 @@ import javax.microedition.khronos.opengles.GL11ExtensionPack; class Paper { private static final String TAG = "Paper"; private static final int ROTATE_FACTOR = 4; - private OverscrollAnimation mAnimationLeft = new OverscrollAnimation(); - private OverscrollAnimation mAnimationRight = new OverscrollAnimation(); + private EdgeAnimation mAnimationLeft = new EdgeAnimation(); + private EdgeAnimation mAnimationRight = new EdgeAnimation(); private int mWidth, mHeight; private float[] mMatrix = new float[16]; public void overScroll(float distance) { + distance /= mWidth; // make it relative to width if (distance < 0) { - mAnimationLeft.scroll(-distance); + mAnimationLeft.onPull(-distance); } else { - mAnimationRight.scroll(distance); + mAnimationRight.onPull(distance); } } - public boolean advanceAnimation(long currentTimeMillis) { - return mAnimationLeft.advanceAnimation(currentTimeMillis) - | mAnimationRight.advanceAnimation(currentTimeMillis); + public void edgeReached(float velocity) { + velocity /= mWidth; // make it relative to width + if (velocity < 0) { + mAnimationRight.onAbsorb(-velocity); + } else { + mAnimationLeft.onAbsorb(velocity); + } + } + + public void onRelease() { + mAnimationLeft.onRelease(); + mAnimationRight.onRelease(); + } + + public boolean advanceAnimation() { + // Note that we use "|" because we want both animations get updated. + return mAnimationLeft.update() | mAnimationRight.update(); } public void setSize(int width, int height) { @@ -56,7 +75,12 @@ class Paper { float left = mAnimationLeft.getValue(); float right = mAnimationRight.getValue(); float screenX = target.x - scrollX; - float t = ((mWidth - screenX) * left - screenX * right) / (mWidth * mWidth); + // We linearly interpolate the value [left, right] for the screenX + // range int [-1/4, 5/4]*mWidth. So if part of the thumbnail is outside + // the screen, we still get some transform. + float x = screenX + mWidth / 4; + int range = 3 * mWidth / 2; + float t = ((range - x) * left - x * right) / range; // compress t to the range (-1, 1) by the function // f(t) = (1 / (1 + e^-t) - 0.5) * 2 // then multiply by 90 to make the range (-45, 45) @@ -71,42 +95,96 @@ class Paper { } } -class OverscrollAnimation { - private static final String TAG = "OverscrollAnimation"; - private static final long START_ANIMATION = -1; - private static final long NO_ANIMATION = -2; - private static final long ANIMATION_DURATION = 500; +// This class follows the structure of frameworks's EdgeEffect class. +class EdgeAnimation { + private static final String TAG = "EdgeAnimation"; + + private static final int STATE_IDLE = 0; + private static final int STATE_PULL = 1; + private static final int STATE_ABSORB = 2; + private static final int STATE_RELEASE = 3; + + // Time it will take the effect to fully done in ms + private static final int ABSORB_TIME = 200; + private static final int RELEASE_TIME = 500; + + private static final float VELOCITY_FACTOR = 0.1f; + + private final Interpolator mInterpolator; + + private int mState; + private long mAnimationStartTime; + private float mValue; - private long mAnimationStartTime = NO_ANIMATION; - private float mVelocity; - private float mCurrentValue; + private float mValueStart; + private float mValueFinish; + private long mStartTime; + private long mDuration; - public void scroll(float distance) { - mAnimationStartTime = START_ANIMATION; - mCurrentValue += distance; + public EdgeAnimation() { + mInterpolator = new DecelerateInterpolator(); + mState = STATE_IDLE; } - public boolean advanceAnimation(long currentTimeMillis) { - if (mAnimationStartTime == NO_ANIMATION) return false; - if (mAnimationStartTime == START_ANIMATION) { - mAnimationStartTime = currentTimeMillis; - return true; - } + private void startAnimation(float start, float finish, long duration, + int newState) { + mValueStart = start; + mValueFinish = finish; + mDuration = duration; + mStartTime = now(); + mState = newState; + } + + // The deltaDistance's magnitude is in the range of -1 (no change) to 1. + // The value 1 is the full length of the view. Negative values means the + // movement is in the opposite direction. + public void onPull(float deltaDistance) { + if (mState == STATE_ABSORB) return; + mValue = Utils.clamp(mValue + deltaDistance, -1.0f, 1.0f); + mState = STATE_PULL; + } + + public void onRelease() { + if (mState == STATE_IDLE || mState == STATE_ABSORB) return; + startAnimation(mValue, 0, RELEASE_TIME, STATE_RELEASE); + } - long deltaTime = currentTimeMillis - mAnimationStartTime; - float t = deltaTime / 100f; - mCurrentValue *= Math.pow(0.5f, t); - mAnimationStartTime = currentTimeMillis; + public void onAbsorb(float velocity) { + float finish = Utils.clamp(mValue + velocity * VELOCITY_FACTOR, + -1.0f, 1.0f); + startAnimation(mValue, finish, ABSORB_TIME, STATE_ABSORB); + } - if (mCurrentValue < 1) { - mAnimationStartTime = NO_ANIMATION; - mCurrentValue = 0; - return false; + public boolean update() { + if (mState == STATE_IDLE) return false; + if (mState == STATE_PULL) return true; + + float t = Utils.clamp((float)(now() - mStartTime) / mDuration, 0.0f, 1.0f); + /* Use linear interpolation for absorb, quadratic for others */ + float interp = (mState == STATE_ABSORB) + ? t : mInterpolator.getInterpolation(t); + + mValue = mValueStart + (mValueFinish - mValueStart) * interp; + + if (t >= 1.0f) { + switch (mState) { + case STATE_ABSORB: + startAnimation(mValue, 0, RELEASE_TIME, STATE_RELEASE); + break; + case STATE_RELEASE: + mState = STATE_IDLE; + break; + } } + return true; } public float getValue() { - return mCurrentValue; + return mValue; + } + + private long now() { + return SystemClock.uptimeMillis(); } } |