/*
* Copyright (C) 2012 www.amsoft.cn
*
* 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.andbase.view.carousel;
import android.content.Context;
import android.view.animation.AnimationUtils;
// TODO: Auto-generated Javadoc
/**
* This class encapsulates rotation. The duration of the rotation can be passed
* in the constructor and specifies the maximum time that the rotation animation
* should take. Past this time, the rotation is automatically moved to its final
* stage and computeRotationOffset() will always return false to indicate that
* scrolling is over.
*/
public class Rotator {
/** The m mode. */
private int mMode;
/** The m start angle. */
private float mStartAngle;
/** The m curr angle. */
private float mCurrAngle;
/** The m start time. */
private long mStartTime;
/** The m duration. */
private long mDuration;
/** The m delta angle. */
private float mDeltaAngle;
/** The m finished. */
private boolean mFinished;
/** The m coeff velocity. */
private float mCoeffVelocity = 0.05f;
/** The m velocity. */
private float mVelocity;
/** The Constant DEFAULT_DURATION. */
private static final int DEFAULT_DURATION = 250;
/** The Constant SCROLL_MODE. */
private static final int SCROLL_MODE = 0;
/** The Constant FLING_MODE. */
private static final int FLING_MODE = 1;
/** The m deceleration. */
private final float mDeceleration = 240.0f;
/**
* Create a Scroller with the specified interpolator. If the interpolator is
* null, the default (viscous) interpolator will be used.
*
* @param context
* the context
*/
public Rotator(Context context) {
mFinished = true;
}
/**
*
* Returns whether the scroller has finished scrolling.
*
* @return True if the scroller has finished scrolling, false otherwise.
*/
public final boolean isFinished() {
return mFinished;
}
/**
* Force the finished field to a particular value.
*
* @param finished
* The new finished value.
*/
public final void forceFinished(boolean finished) {
mFinished = finished;
}
/**
* Returns how long the scroll event will take, in milliseconds.
*
* @return The duration of the scroll in milliseconds.
*/
public final long getDuration() {
return mDuration;
}
/**
* Returns the current X offset in the scroll.
*
* @return The new X offset as an absolute distance from the origin.
*/
public final float getCurrAngle() {
return mCurrAngle;
}
/**
* Gets the curr velocity.
*
* @return The original velocity less the deceleration. Result may be
* negative.
* @hide Returns the current velocity.
*/
public float getCurrVelocity() {
return mCoeffVelocity * mVelocity - mDeceleration * timePassed() /*
* /
* 2000.0f
*/;
}
/**
* Returns the start X offset in the scroll.
*
* @return The start X offset as an absolute distance from the origin.
*/
public final float getStartAngle() {
return mStartAngle;
}
/**
* Returns the time elapsed since the beginning of the scrolling.
*
* @return The elapsed time in milliseconds.
*/
public int timePassed() {
return (int) (AnimationUtils.currentAnimationTimeMillis() - mStartTime);
}
/**
* Extend the scroll animation. This allows a running animation to scroll
* further and longer, when used with {@link #setFinalX(int)} or
* {@link #setFinalY(int)}.
*
* @param extend
* Additional time to scroll in milliseconds.
* @see #setFinalX(int)
* @see #setFinalY(int)
*/
public void extendDuration(int extend) {
int passed = timePassed();
mDuration = passed + extend;
mFinished = false;
}
/**
* Stops the animation. Contrary to {@link #forceFinished(boolean)},
* aborting the animating cause the scroller to move to the final x and y
* position
*
* @see #forceFinished(boolean)
*/
public void abortAnimation() {
mFinished = true;
}
/**
* Call this when you want to know the new location. If it returns true, the
* animation is not yet finished. loc will be altered to provide the new
* location.
*
* @return true, if successful
*/
public boolean computeAngleOffset() {
if (mFinished) {
return false;
}
long systemClock = AnimationUtils.currentAnimationTimeMillis();
long timePassed = systemClock - mStartTime;
if (timePassed < mDuration) {
switch (mMode) {
case SCROLL_MODE:
float sc = (float) timePassed / mDuration;
mCurrAngle = mStartAngle + Math.round(mDeltaAngle * sc);
break;
case FLING_MODE:
float timePassedSeconds = timePassed / 1000.0f;
float distance;
if (mVelocity < 0) {
distance = mCoeffVelocity
* mVelocity
* timePassedSeconds
- (mDeceleration * timePassedSeconds
* timePassedSeconds / 2.0f);
} else {
distance = -mCoeffVelocity
* mVelocity
* timePassedSeconds
- (mDeceleration * timePassedSeconds
* timePassedSeconds / 2.0f);
}
mCurrAngle = mStartAngle - Math.signum(mVelocity)
* Math.round(distance);
break;
}
return true;
} else {
mFinished = true;
return false;
}
}
/**
* Start scrolling by providing a starting point and the distance to travel.
*
* @param startAngle
* the start angle
* @param dAngle
* the d angle
* @param duration
* Duration of the scroll in milliseconds.
*/
public void startRotate(float startAngle, float dAngle, int duration) {
mMode = SCROLL_MODE;
mFinished = false;
mDuration = duration;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
mStartAngle = startAngle;
mDeltaAngle = dAngle;
}
/**
* Start scrolling by providing a starting point and the distance to travel.
* The scroll will use the default value of 250 milliseconds for the
* duration.
*
* @param startAngle
* the start angle
* @param dAngle
* the d angle
*/
public void startRotate(float startAngle, float dAngle) {
startRotate(startAngle, dAngle, DEFAULT_DURATION);
}
/**
* Start scrolling based on a fling gesture. The distance travelled will
* depend on the initial velocity of the fling.
*
* @param velocityAngle
* Initial velocity of the fling (X) measured in pixels per
* second.
*/
public void fling(float velocityAngle) {
mMode = FLING_MODE;
mFinished = false;
float velocity = velocityAngle;
mVelocity = velocity;
mDuration = (int) (1000.0f * Math.sqrt(2.0f * mCoeffVelocity
* Math.abs(velocity) / mDeceleration));
mStartTime = AnimationUtils.currentAnimationTimeMillis();
}
}