All Downloads are FREE. Search and download functionalities are using the official Maven repository.

android.view.animation.Animation Maven / Gradle / Ivy

/*
 * Copyright (C) 2006 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 android.view.animation;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.RectF;
import android.os.Handler;
import android.os.SystemProperties;
import android.util.AttributeSet;
import android.util.TypedValue;
import dalvik.system.CloseGuard;

/**
 * Abstraction for an Animation that can be applied to Views, Surfaces, or
 * other objects. See the {@link android.view.animation animation package
 * description file}.
 */
public abstract class Animation implements Cloneable {
    /**
     * Repeat the animation indefinitely.
     */
    public static final int INFINITE = -1;

    /**
     * When the animation reaches the end and the repeat count is INFINTE_REPEAT
     * or a positive value, the animation restarts from the beginning.
     */
    public static final int RESTART = 1;

    /**
     * When the animation reaches the end and the repeat count is INFINTE_REPEAT
     * or a positive value, the animation plays backward (and then forward again).
     */
    public static final int REVERSE = 2;

    /**
     * Can be used as the start time to indicate the start time should be the current
     * time when {@link #getTransformation(long, Transformation)} is invoked for the
     * first animation frame. This can is useful for short animations.
     */
    public static final int START_ON_FIRST_FRAME = -1;

    /**
     * The specified dimension is an absolute number of pixels.
     */
    public static final int ABSOLUTE = 0;

    /**
     * The specified dimension holds a float and should be multiplied by the
     * height or width of the object being animated.
     */
    public static final int RELATIVE_TO_SELF = 1;

    /**
     * The specified dimension holds a float and should be multiplied by the
     * height or width of the parent of the object being animated.
     */
    public static final int RELATIVE_TO_PARENT = 2;

    /**
     * Requests that the content being animated be kept in its current Z
     * order.
     */
    public static final int ZORDER_NORMAL = 0;
    
    /**
     * Requests that the content being animated be forced on top of all other
     * content for the duration of the animation.
     */
    public static final int ZORDER_TOP = 1;
    
    /**
     * Requests that the content being animated be forced under all other
     * content for the duration of the animation.
     */
    public static final int ZORDER_BOTTOM = -1;

    private static final boolean USE_CLOSEGUARD
            = SystemProperties.getBoolean("log.closeguard.Animation", false);

    /**
     * Set by {@link #getTransformation(long, Transformation)} when the animation ends.
     */
    boolean mEnded = false;

    /**
     * Set by {@link #getTransformation(long, Transformation)} when the animation starts.
     */
    boolean mStarted = false;

    /**
     * Set by {@link #getTransformation(long, Transformation)} when the animation repeats
     * in REVERSE mode.
     */
    boolean mCycleFlip = false;

    /**
     * This value must be set to true by {@link #initialize(int, int, int, int)}. It
     * indicates the animation was successfully initialized and can be played.
     */
    boolean mInitialized = false;

    /**
     * Indicates whether the animation transformation should be applied before the
     * animation starts. The value of this variable is only relevant if mFillEnabled is true;
     * otherwise it is assumed to be true.
     */
    boolean mFillBefore = true;

    /**
     * Indicates whether the animation transformation should be applied after the
     * animation ends.
     */
    boolean mFillAfter = false;

    /**
     * Indicates whether fillBefore should be taken into account.
     */
    boolean mFillEnabled = false;    

    /**
     * The time in milliseconds at which the animation must start;
     */
    long mStartTime = -1;

    /**
     * The delay in milliseconds after which the animation must start. When the
     * start offset is > 0, the start time of the animation is startTime + startOffset.
     */
    long mStartOffset;

    /**
     * The duration of one animation cycle in milliseconds.
     */
    long mDuration;

    /**
     * The number of times the animation must repeat. By default, an animation repeats
     * indefinitely.
     */
    int mRepeatCount = 0;

    /**
     * Indicates how many times the animation was repeated.
     */
    int mRepeated = 0;

    /**
     * The behavior of the animation when it repeats. The repeat mode is either
     * {@link #RESTART} or {@link #REVERSE}.
     *
     */
    int mRepeatMode = RESTART;

    /**
     * The interpolator used by the animation to smooth the movement.
     */
    Interpolator mInterpolator;

    /**
     * The animation listener to be notified when the animation starts, ends or repeats.
     */
    AnimationListener mListener;

    /**
     * Desired Z order mode during animation.
     */
    private int mZAdjustment;

    /**
     * Desired background color behind animation.
     */
    private int mBackgroundColor;

    /**
     * scalefactor to apply to pivot points, etc. during animation. Subclasses retrieve the
     * value via getScaleFactor().
     */
    private float mScaleFactor = 1f;

    /**
     * Don't animate the wallpaper.
     */
    private boolean mDetachWallpaper = false;

    private boolean mMore = true;
    private boolean mOneMoreTime = true;

    RectF mPreviousRegion = new RectF();
    RectF mRegion = new RectF();
    Transformation mTransformation = new Transformation();
    Transformation mPreviousTransformation = new Transformation();

    private final CloseGuard guard = CloseGuard.get();

    private Handler mListenerHandler;
    private Runnable mOnStart;
    private Runnable mOnRepeat;
    private Runnable mOnEnd;

    /**
     * Creates a new animation with a duration of 0ms, the default interpolator, with
     * fillBefore set to true and fillAfter set to false
     */
    public Animation() {
        ensureInterpolator();
    }

    /**
     * Creates a new animation whose parameters come from the specified context and
     * attributes set.
     *
     * @param context the application environment
     * @param attrs the set of attributes holding the animation parameters
     */
    public Animation(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Animation);

        setDuration((long) a.getInt(com.android.internal.R.styleable.Animation_duration, 0));
        setStartOffset((long) a.getInt(com.android.internal.R.styleable.Animation_startOffset, 0));
        
        setFillEnabled(a.getBoolean(com.android.internal.R.styleable.Animation_fillEnabled, mFillEnabled));
        setFillBefore(a.getBoolean(com.android.internal.R.styleable.Animation_fillBefore, mFillBefore));
        setFillAfter(a.getBoolean(com.android.internal.R.styleable.Animation_fillAfter, mFillAfter));

        setRepeatCount(a.getInt(com.android.internal.R.styleable.Animation_repeatCount, mRepeatCount));
        setRepeatMode(a.getInt(com.android.internal.R.styleable.Animation_repeatMode, RESTART));

        setZAdjustment(a.getInt(com.android.internal.R.styleable.Animation_zAdjustment, ZORDER_NORMAL));
        
        setBackgroundColor(a.getInt(com.android.internal.R.styleable.Animation_background, 0));

        setDetachWallpaper(a.getBoolean(com.android.internal.R.styleable.Animation_detachWallpaper, false));

        final int resID = a.getResourceId(com.android.internal.R.styleable.Animation_interpolator, 0);

        a.recycle();

        if (resID > 0) {
            setInterpolator(context, resID);
        }

        ensureInterpolator();
    }

    @Override
    protected Animation clone() throws CloneNotSupportedException {
        final Animation animation = (Animation) super.clone();
        animation.mPreviousRegion = new RectF();
        animation.mRegion = new RectF();
        animation.mTransformation = new Transformation();
        animation.mPreviousTransformation = new Transformation();
        return animation;
    }

    /**
     * Reset the initialization state of this animation.
     *
     * @see #initialize(int, int, int, int)
     */
    public void reset() {
        mPreviousRegion.setEmpty();
        mPreviousTransformation.clear();
        mInitialized = false;
        mCycleFlip = false;
        mRepeated = 0;
        mMore = true;
        mOneMoreTime = true;
        mListenerHandler = null;
    }

    /**
     * Cancel the animation. Cancelling an animation invokes the animation
     * listener, if set, to notify the end of the animation.
     * 
     * If you cancel an animation manually, you must call {@link #reset()}
     * before starting the animation again.
     * 
     * @see #reset() 
     * @see #start() 
     * @see #startNow() 
     */
    public void cancel() {
        if (mStarted && !mEnded) {
            fireAnimationEnd();
            mEnded = true;
            guard.close();
        }
        // Make sure we move the animation to the end
        mStartTime = Long.MIN_VALUE;
        mMore = mOneMoreTime = false;
    }

    /**
     * @hide
     */
    public void detach() {
        if (mStarted && !mEnded) {
            mEnded = true;
            guard.close();
            fireAnimationEnd();
        }
    }

    /**
     * Whether or not the animation has been initialized.
     *
     * @return Has this animation been initialized.
     * @see #initialize(int, int, int, int)
     */
    public boolean isInitialized() {
        return mInitialized;
    }

    /**
     * Initialize this animation with the dimensions of the object being
     * animated as well as the objects parents. (This is to support animation
     * sizes being specified relative to these dimensions.)
     *
     * 

Objects that interpret Animations should call this method when * the sizes of the object being animated and its parent are known, and * before calling {@link #getTransformation}. * * * @param width Width of the object being animated * @param height Height of the object being animated * @param parentWidth Width of the animated object's parent * @param parentHeight Height of the animated object's parent */ public void initialize(int width, int height, int parentWidth, int parentHeight) { reset(); mInitialized = true; } /** * Sets the handler used to invoke listeners. * * @hide */ public void setListenerHandler(Handler handler) { if (mListenerHandler == null) { mOnStart = new Runnable() { public void run() { if (mListener != null) { mListener.onAnimationStart(Animation.this); } } }; mOnRepeat = new Runnable() { public void run() { if (mListener != null) { mListener.onAnimationRepeat(Animation.this); } } }; mOnEnd = new Runnable() { public void run() { if (mListener != null) { mListener.onAnimationEnd(Animation.this); } } }; } mListenerHandler = handler; } /** * Sets the acceleration curve for this animation. The interpolator is loaded as * a resource from the specified context. * * @param context The application environment * @param resID The resource identifier of the interpolator to load * @attr ref android.R.styleable#Animation_interpolator */ public void setInterpolator(Context context, int resID) { setInterpolator(AnimationUtils.loadInterpolator(context, resID)); } /** * Sets the acceleration curve for this animation. Defaults to a linear * interpolation. * * @param i The interpolator which defines the acceleration curve * @attr ref android.R.styleable#Animation_interpolator */ public void setInterpolator(Interpolator i) { mInterpolator = i; } /** * When this animation should start relative to the start time. This is most * useful when composing complex animations using an {@link AnimationSet } * where some of the animations components start at different times. * * @param startOffset When this Animation should start, in milliseconds from * the start time of the root AnimationSet. * @attr ref android.R.styleable#Animation_startOffset */ public void setStartOffset(long startOffset) { mStartOffset = startOffset; } /** * How long this animation should last. The duration cannot be negative. * * @param durationMillis Duration in milliseconds * * @throws java.lang.IllegalArgumentException if the duration is < 0 * * @attr ref android.R.styleable#Animation_duration */ public void setDuration(long durationMillis) { if (durationMillis < 0) { throw new IllegalArgumentException("Animation duration cannot be negative"); } mDuration = durationMillis; } /** * Ensure that the duration that this animation will run is not longer * than durationMillis. In addition to adjusting the duration * itself, this ensures that the repeat count also will not make it run * longer than the given time. * * @param durationMillis The maximum duration the animation is allowed * to run. */ public void restrictDuration(long durationMillis) { // If we start after the duration, then we just won't run. if (mStartOffset > durationMillis) { mStartOffset = durationMillis; mDuration = 0; mRepeatCount = 0; return; } long dur = mDuration + mStartOffset; if (dur > durationMillis) { mDuration = durationMillis-mStartOffset; dur = durationMillis; } // If the duration is 0 or less, then we won't run. if (mDuration <= 0) { mDuration = 0; mRepeatCount = 0; return; } // Reduce the number of repeats to keep below the maximum duration. // The comparison between mRepeatCount and duration is to catch // overflows after multiplying them. if (mRepeatCount < 0 || mRepeatCount > durationMillis || (dur*mRepeatCount) > durationMillis) { // Figure out how many times to do the animation. Subtract 1 since // repeat count is the number of times to repeat so 0 runs once. mRepeatCount = (int)(durationMillis/dur) - 1; if (mRepeatCount < 0) { mRepeatCount = 0; } } } /** * How much to scale the duration by. * * @param scale The amount to scale the duration. */ public void scaleCurrentDuration(float scale) { mDuration = (long) (mDuration * scale); mStartOffset = (long) (mStartOffset * scale); } /** * When this animation should start. When the start time is set to * {@link #START_ON_FIRST_FRAME}, the animation will start the first time * {@link #getTransformation(long, Transformation)} is invoked. The time passed * to this method should be obtained by calling * {@link AnimationUtils#currentAnimationTimeMillis()} instead of * {@link System#currentTimeMillis()}. * * @param startTimeMillis the start time in milliseconds */ public void setStartTime(long startTimeMillis) { mStartTime = startTimeMillis; mStarted = mEnded = false; mCycleFlip = false; mRepeated = 0; mMore = true; } /** * Convenience method to start the animation the first time * {@link #getTransformation(long, Transformation)} is invoked. */ public void start() { setStartTime(-1); } /** * Convenience method to start the animation at the current time in * milliseconds. */ public void startNow() { setStartTime(AnimationUtils.currentAnimationTimeMillis()); } /** * Defines what this animation should do when it reaches the end. This * setting is applied only when the repeat count is either greater than * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}. * * @param repeatMode {@link #RESTART} or {@link #REVERSE} * @attr ref android.R.styleable#Animation_repeatMode */ public void setRepeatMode(int repeatMode) { mRepeatMode = repeatMode; } /** * Sets how many times the animation should be repeated. If the repeat * count is 0, the animation is never repeated. If the repeat count is * greater than 0 or {@link #INFINITE}, the repeat mode will be taken * into account. The repeat count is 0 by default. * * @param repeatCount the number of times the animation should be repeated * @attr ref android.R.styleable#Animation_repeatCount */ public void setRepeatCount(int repeatCount) { if (repeatCount < 0) { repeatCount = INFINITE; } mRepeatCount = repeatCount; } /** * If fillEnabled is true, this animation will apply the value of fillBefore. * * @return true if the animation will take fillBefore into account * @attr ref android.R.styleable#Animation_fillEnabled */ public boolean isFillEnabled() { return mFillEnabled; } /** * If fillEnabled is true, the animation will apply the value of fillBefore. * Otherwise, fillBefore is ignored and the animation * transformation is always applied until the animation ends. * * @param fillEnabled true if the animation should take the value of fillBefore into account * @attr ref android.R.styleable#Animation_fillEnabled * * @see #setFillBefore(boolean) * @see #setFillAfter(boolean) */ public void setFillEnabled(boolean fillEnabled) { mFillEnabled = fillEnabled; } /** * If fillBefore is true, this animation will apply its transformation * before the start time of the animation. Defaults to true if * {@link #setFillEnabled(boolean)} is not set to true. * Note that this applies when using an {@link * android.view.animation.AnimationSet AnimationSet} to chain * animations. The transformation is not applied before the AnimationSet * itself starts. * * @param fillBefore true if the animation should apply its transformation before it starts * @attr ref android.R.styleable#Animation_fillBefore * * @see #setFillEnabled(boolean) */ public void setFillBefore(boolean fillBefore) { mFillBefore = fillBefore; } /** * If fillAfter is true, the transformation that this animation performed * will persist when it is finished. Defaults to false if not set. * Note that this applies to individual animations and when using an {@link * android.view.animation.AnimationSet AnimationSet} to chain * animations. * * @param fillAfter true if the animation should apply its transformation after it ends * @attr ref android.R.styleable#Animation_fillAfter * * @see #setFillEnabled(boolean) */ public void setFillAfter(boolean fillAfter) { mFillAfter = fillAfter; } /** * Set the Z ordering mode to use while running the animation. * * @param zAdjustment The desired mode, one of {@link #ZORDER_NORMAL}, * {@link #ZORDER_TOP}, or {@link #ZORDER_BOTTOM}. * @attr ref android.R.styleable#Animation_zAdjustment */ public void setZAdjustment(int zAdjustment) { mZAdjustment = zAdjustment; } /** * Set background behind animation. * * @param bg The background color. If 0, no background. Currently must * be black, with any desired alpha level. */ public void setBackgroundColor(int bg) { mBackgroundColor = bg; } /** * The scale factor is set by the call to getTransformation. Overrides of * {@link #getTransformation(long, Transformation, float)} will get this value * directly. Overrides of {@link #applyTransformation(float, Transformation)} can * call this method to get the value. * * @return float The scale factor that should be applied to pre-scaled values in * an Animation such as the pivot points in {@link ScaleAnimation} and {@link RotateAnimation}. */ protected float getScaleFactor() { return mScaleFactor; } /** * If detachWallpaper is true, and this is a window animation of a window * that has a wallpaper background, then the window will be detached from * the wallpaper while it runs. That is, the animation will only be applied * to the window, and the wallpaper behind it will remain static. * * @param detachWallpaper true if the wallpaper should be detached from the animation * @attr ref android.R.styleable#Animation_detachWallpaper */ public void setDetachWallpaper(boolean detachWallpaper) { mDetachWallpaper = detachWallpaper; } /** * Gets the acceleration curve type for this animation. * * @return the {@link Interpolator} associated to this animation * @attr ref android.R.styleable#Animation_interpolator */ public Interpolator getInterpolator() { return mInterpolator; } /** * When this animation should start. If the animation has not startet yet, * this method might return {@link #START_ON_FIRST_FRAME}. * * @return the time in milliseconds when the animation should start or * {@link #START_ON_FIRST_FRAME} */ public long getStartTime() { return mStartTime; } /** * How long this animation should last * * @return the duration in milliseconds of the animation * @attr ref android.R.styleable#Animation_duration */ public long getDuration() { return mDuration; } /** * When this animation should start, relative to StartTime * * @return the start offset in milliseconds * @attr ref android.R.styleable#Animation_startOffset */ public long getStartOffset() { return mStartOffset; } /** * Defines what this animation should do when it reaches the end. * * @return either one of {@link #REVERSE} or {@link #RESTART} * @attr ref android.R.styleable#Animation_repeatMode */ public int getRepeatMode() { return mRepeatMode; } /** * Defines how many times the animation should repeat. The default value * is 0. * * @return the number of times the animation should repeat, or {@link #INFINITE} * @attr ref android.R.styleable#Animation_repeatCount */ public int getRepeatCount() { return mRepeatCount; } /** * If fillBefore is true, this animation will apply its transformation * before the start time of the animation. If fillBefore is false and * {@link #isFillEnabled() fillEnabled} is true, the transformation will not be applied until * the start time of the animation. * * @return true if the animation applies its transformation before it starts * @attr ref android.R.styleable#Animation_fillBefore */ public boolean getFillBefore() { return mFillBefore; } /** * If fillAfter is true, this animation will apply its transformation * after the end time of the animation. * * @return true if the animation applies its transformation after it ends * @attr ref android.R.styleable#Animation_fillAfter */ public boolean getFillAfter() { return mFillAfter; } /** * Returns the Z ordering mode to use while running the animation as * previously set by {@link #setZAdjustment}. * * @return Returns one of {@link #ZORDER_NORMAL}, * {@link #ZORDER_TOP}, or {@link #ZORDER_BOTTOM}. * @attr ref android.R.styleable#Animation_zAdjustment */ public int getZAdjustment() { return mZAdjustment; } /** * Returns the background color behind the animation. */ public int getBackgroundColor() { return mBackgroundColor; } /** * Return value of {@link #setDetachWallpaper(boolean)}. * @attr ref android.R.styleable#Animation_detachWallpaper */ public boolean getDetachWallpaper() { return mDetachWallpaper; } /** *

Indicates whether or not this animation will affect the transformation * matrix. For instance, a fade animation will not affect the matrix whereas * a scale animation will.

* * @return true if this animation will change the transformation matrix */ public boolean willChangeTransformationMatrix() { // assume we will change the matrix return true; } /** *

Indicates whether or not this animation will affect the bounds of the * animated view. For instance, a fade animation will not affect the bounds * whereas a 200% scale animation will.

* * @return true if this animation will change the view's bounds */ public boolean willChangeBounds() { // assume we will change the bounds return true; } /** *

Binds an animation listener to this animation. The animation listener * is notified of animation events such as the end of the animation or the * repetition of the animation.

* * @param listener the animation listener to be notified */ public void setAnimationListener(AnimationListener listener) { mListener = listener; } /** * Gurantees that this animation has an interpolator. Will use * a AccelerateDecelerateInterpolator is nothing else was specified. */ protected void ensureInterpolator() { if (mInterpolator == null) { mInterpolator = new AccelerateDecelerateInterpolator(); } } /** * Compute a hint at how long the entire animation may last, in milliseconds. * Animations can be written to cause themselves to run for a different * duration than what is computed here, but generally this should be * accurate. */ public long computeDurationHint() { return (getStartOffset() + getDuration()) * (getRepeatCount() + 1); } /** * Gets the transformation to apply at a specified point in time. Implementations of this * method should always replace the specified Transformation or document they are doing * otherwise. * * @param currentTime Where we are in the animation. This is wall clock time. * @param outTransformation A transformation object that is provided by the * caller and will be filled in by the animation. * @return True if the animation is still running */ public boolean getTransformation(long currentTime, Transformation outTransformation) { if (mStartTime == -1) { mStartTime = currentTime; } final long startOffset = getStartOffset(); final long duration = mDuration; float normalizedTime; if (duration != 0) { normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) / (float) duration; } else { // time is a step-change with a zero duration normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f; } final boolean expired = normalizedTime >= 1.0f; mMore = !expired; if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f); if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) { if (!mStarted) { fireAnimationStart(); mStarted = true; if (USE_CLOSEGUARD) { guard.open("cancel or detach or getTransformation"); } } if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f); if (mCycleFlip) { normalizedTime = 1.0f - normalizedTime; } final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime); applyTransformation(interpolatedTime, outTransformation); } if (expired) { if (mRepeatCount == mRepeated) { if (!mEnded) { mEnded = true; guard.close(); fireAnimationEnd(); } } else { if (mRepeatCount > 0) { mRepeated++; } if (mRepeatMode == REVERSE) { mCycleFlip = !mCycleFlip; } mStartTime = -1; mMore = true; fireAnimationRepeat(); } } if (!mMore && mOneMoreTime) { mOneMoreTime = false; return true; } return mMore; } private void fireAnimationStart() { if (mListener != null) { if (mListenerHandler == null) mListener.onAnimationStart(this); else mListenerHandler.postAtFrontOfQueue(mOnStart); } } private void fireAnimationRepeat() { if (mListener != null) { if (mListenerHandler == null) mListener.onAnimationRepeat(this); else mListenerHandler.postAtFrontOfQueue(mOnRepeat); } } private void fireAnimationEnd() { if (mListener != null) { if (mListenerHandler == null) mListener.onAnimationEnd(this); else mListenerHandler.postAtFrontOfQueue(mOnEnd); } } /** * Gets the transformation to apply at a specified point in time. Implementations of this * method should always replace the specified Transformation or document they are doing * otherwise. * * @param currentTime Where we are in the animation. This is wall clock time. * @param outTransformation A transformation object that is provided by the * caller and will be filled in by the animation. * @param scale Scaling factor to apply to any inputs to the transform operation, such * pivot points being rotated or scaled around. * @return True if the animation is still running */ public boolean getTransformation(long currentTime, Transformation outTransformation, float scale) { mScaleFactor = scale; return getTransformation(currentTime, outTransformation); } /** *

Indicates whether this animation has started or not.

* * @return true if the animation has started, false otherwise */ public boolean hasStarted() { return mStarted; } /** *

Indicates whether this animation has ended or not.

* * @return true if the animation has ended, false otherwise */ public boolean hasEnded() { return mEnded; } /** * Helper for getTransformation. Subclasses should implement this to apply * their transforms given an interpolation value. Implementations of this * method should always replace the specified Transformation or document * they are doing otherwise. * * @param interpolatedTime The value of the normalized time (0.0 to 1.0) * after it has been run through the interpolation function. * @param t The Transformation object to fill in with the current * transforms. */ protected void applyTransformation(float interpolatedTime, Transformation t) { } /** * Convert the information in the description of a size to an actual * dimension * * @param type One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or * Animation.RELATIVE_TO_PARENT. * @param value The dimension associated with the type parameter * @param size The size of the object being animated * @param parentSize The size of the parent of the object being animated * @return The dimension to use for the animation */ protected float resolveSize(int type, float value, int size, int parentSize) { switch (type) { case ABSOLUTE: return value; case RELATIVE_TO_SELF: return size * value; case RELATIVE_TO_PARENT: return parentSize * value; default: return value; } } /** * @param left * @param top * @param right * @param bottom * @param invalidate * @param transformation * * @hide */ public void getInvalidateRegion(int left, int top, int right, int bottom, RectF invalidate, Transformation transformation) { final RectF tempRegion = mRegion; final RectF previousRegion = mPreviousRegion; invalidate.set(left, top, right, bottom); transformation.getMatrix().mapRect(invalidate); // Enlarge the invalidate region to account for rounding errors invalidate.inset(-1.0f, -1.0f); tempRegion.set(invalidate); invalidate.union(previousRegion); previousRegion.set(tempRegion); final Transformation tempTransformation = mTransformation; final Transformation previousTransformation = mPreviousTransformation; tempTransformation.set(transformation); transformation.set(previousTransformation); previousTransformation.set(tempTransformation); } /** * @param left * @param top * @param right * @param bottom * * @hide */ public void initializeInvalidateRegion(int left, int top, int right, int bottom) { final RectF region = mPreviousRegion; region.set(left, top, right, bottom); // Enlarge the invalidate region to account for rounding errors region.inset(-1.0f, -1.0f); if (mFillBefore) { final Transformation previousTransformation = mPreviousTransformation; applyTransformation(mInterpolator.getInterpolation(0.0f), previousTransformation); } } protected void finalize() throws Throwable { try { if (guard != null) { guard.warnIfOpen(); } } finally { super.finalize(); } } /** * Return true if this animation changes the view's alpha property. * * @hide */ public boolean hasAlpha() { return false; } /** * Utility class to parse a string description of a size. */ protected static class Description { /** * One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or * Animation.RELATIVE_TO_PARENT. */ public int type; /** * The absolute or relative dimension for this Description. */ public float value; /** * Size descriptions can appear inthree forms: *
    *
  1. An absolute size. This is represented by a number.
  2. *
  3. A size relative to the size of the object being animated. This * is represented by a number followed by "%".
  4. * *
  5. A size relative to the size of the parent of object being * animated. This is represented by a number followed by "%p".
  6. *
* @param value The typed value to parse * @return The parsed version of the description */ static Description parseValue(TypedValue value) { Description d = new Description(); if (value == null) { d.type = ABSOLUTE; d.value = 0; } else { if (value.type == TypedValue.TYPE_FRACTION) { d.type = (value.data & TypedValue.COMPLEX_UNIT_MASK) == TypedValue.COMPLEX_UNIT_FRACTION_PARENT ? RELATIVE_TO_PARENT : RELATIVE_TO_SELF; d.value = TypedValue.complexToFloat(value.data); return d; } else if (value.type == TypedValue.TYPE_FLOAT) { d.type = ABSOLUTE; d.value = value.getFloat(); return d; } else if (value.type >= TypedValue.TYPE_FIRST_INT && value.type <= TypedValue.TYPE_LAST_INT) { d.type = ABSOLUTE; d.value = value.data; return d; } } d.type = ABSOLUTE; d.value = 0.0f; return d; } } /** *

An animation listener receives notifications from an animation. * Notifications indicate animation related events, such as the end or the * repetition of the animation.

*/ public static interface AnimationListener { /** *

Notifies the start of the animation.

* * @param animation The started animation. */ void onAnimationStart(Animation animation); /** *

Notifies the end of the animation. This callback is not invoked * for animations with repeat count set to INFINITE.

* * @param animation The animation which reached its end. */ void onAnimationEnd(Animation animation); /** *

Notifies the repetition of the animation.

* * @param animation The animation which was repeated. */ void onAnimationRepeat(Animation animation); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy