Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * Copyright (C) 2010 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.actionbarsherlock.internal.nineoldandroids.animation;
  
  import android.os.Looper;
  
  import java.util.HashMap;

This class provides a simple timing engine for running animations which calculate animated values and set them on target objects.

There is a single timing pulse that all animations use. It runs in a custom handler to ensure that property changes happen on the UI thread.

By default, ValueAnimator uses non-linear time interpolation, via the AccelerateDecelerateInterpolator class, which accelerates into and decelerates out of an animation. This behavior can be changed by calling ValueAnimator.setInterpolator(TimeInterpolator).

  
  @SuppressWarnings({"rawtypes""unchecked"})
  public class ValueAnimator extends Animator {

    
Internal constants
  
  
      /*
       * The default amount of time in ms between animation frames
       */
      private static final long DEFAULT_FRAME_DELAY = 10;

    
Messages sent to timing handler: START is sent when an animation first begins, FRAME is sent by the handler to itself to process the next animation frame
  
      static final int ANIMATION_START = 0;
      static final int ANIMATION_FRAME = 1;

    
Values used with internal variable mPlayingState to indicate the current state of an animation.
  
      static final int STOPPED    = 0; // Not yet playing
      static final int RUNNING    = 1; // Playing normally
      static final int SEEKED     = 2; // Seeked to some time value
  
    
Internal variables NOTE: This object implements the clone() method, making a deep copy of any referenced objects. As other non-trivial fields are added to this class, make sure to add logic to clone() to make deep copies of them.
  
  
      // The first time that the animation's animateFrame() method is called. This time is used to
      // determine elapsed time (and therefore the elapsed fraction) in subsequent calls
      // to animateFrame()
      long mStartTime;

    
Set when setCurrentPlayTime() is called. If negative, animation is not currently seeked to a value.
  
      long mSeekTime = -1;
  
      // TODO: We access the following ThreadLocal variables often, some of them on every update.
      // If ThreadLocal access is significantly expensive, we may want to put all of these
      // fields into a structure sot hat we just access ThreadLocal once to get the reference
      // to that structure, then access the structure directly for each field.
  
      // The static sAnimationHandler processes the internal timing loop on which all animations
      // are based
      private static ThreadLocal<AnimationHandlersAnimationHandler =
              new ThreadLocal<AnimationHandler>();
  
      // The per-thread list of all active animations
      private static final ThreadLocal<ArrayList<ValueAnimator>> sAnimations =
             new ThreadLocal<ArrayList<ValueAnimator>>() {
                 @Override
                 protected ArrayList<ValueAnimatorinitialValue() {
                     return new ArrayList<ValueAnimator>();
                 }
             };
 
     // The per-thread set of animations to be started on the next animation frame
     private static final ThreadLocal<ArrayList<ValueAnimator>> sPendingAnimations =
             new ThreadLocal<ArrayList<ValueAnimator>>() {
                 @Override
                 protected ArrayList<ValueAnimatorinitialValue() {
                     return new ArrayList<ValueAnimator>();
                 }
             };

    
Internal per-thread collections used to avoid set collisions as animations start and end while being processed.
 
     private static final ThreadLocal<ArrayList<ValueAnimator>> sDelayedAnims =
             new ThreadLocal<ArrayList<ValueAnimator>>() {
                 @Override
                 protected ArrayList<ValueAnimatorinitialValue() {
                     return new ArrayList<ValueAnimator>();
                 }
             };
 
     private static final ThreadLocal<ArrayList<ValueAnimator>> sEndingAnims =
             new ThreadLocal<ArrayList<ValueAnimator>>() {
                 @Override
                 protected ArrayList<ValueAnimatorinitialValue() {
                     return new ArrayList<ValueAnimator>();
                 }
             };
 
     private static final ThreadLocal<ArrayList<ValueAnimator>> sReadyAnims =
             new ThreadLocal<ArrayList<ValueAnimator>>() {
                 @Override
                 protected ArrayList<ValueAnimatorinitialValue() {
                     return new ArrayList<ValueAnimator>();
                 }
             };
 
     // The time interpolator to be used if none is set on the animation
     private static final /*Time*/Interpolator sDefaultInterpolator =
             new AccelerateDecelerateInterpolator();
 
     // type evaluators for the primitive types handled by this implementation
     //private static final TypeEvaluator sIntEvaluator = new IntEvaluator();
     //private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator();
 
    
Used to indicate whether the animation is currently playing in reverse. This causes the elapsed fraction to be inverted to calculate the appropriate values.
 
     private boolean mPlayingBackwards = false;

    
This variable tracks the current iteration that is playing. When mCurrentIteration exceeds the repeatCount (if repeatCount!=INFINITE), the animation ends
 
     private int mCurrentIteration = 0;

    
Tracks current elapsed/eased fraction, for querying in getAnimatedFraction().
 
     private float mCurrentFraction = 0f;

    
Tracks whether a startDelay'd animation has begun playing through the startDelay.
 
     private boolean mStartedDelay = false;

    
Tracks the time at which the animation began playing through its startDelay. This is different from the mStartTime variable, which is used to track when the animation became active (which is when the startDelay expired and the animation was added to the active animations list).
 
     private long mDelayStartTime;

    
Flag that represents the current state of the animation. Used to figure out when to start an animation (if state == STOPPED). Also used to end an animation that has been cancel()'d or end()'d since the last animation frame. Possible values are STOPPED, RUNNING, SEEKED.
 
     int mPlayingState = ;

    
Additional playing state to indicate whether an animator has been start()'d. There is some lag between a call to start() and the first animation frame. We should still note that the animation has been started, even if it's first animation frame has not yet happened, and reflect that state in isRunning(). Note that delayed animations are different: they are not started until their first animation frame, which occurs after their delay elapses.
 
     private boolean mRunning = false;

    
Additional playing state to indicate whether an animator has been start()'d, whether or not there is a nonzero startDelay.
 
     private boolean mStarted = false;

    
Flag that denotes whether the animation is set up and ready to go. Used to set up animation that has not yet been started.
 
     boolean mInitialized = false;
 
     //
     // Backing variables
     //
 
     // How long the animation should last in ms
     private long mDuration = 300;
 
     // The amount of time in ms to delay starting the animation after start() is called
     private long mStartDelay = 0;
 
     // The number of milliseconds between animation frames
     private static long sFrameDelay = ;
 
     // The number of times the animation will repeat. The default is 0, which means the animation
     // will play only once
     private int mRepeatCount = 0;

    
The type of repetition that will occur when repeatMode is nonzero. RESTART means the animation will start from the beginning on every new cycle. REVERSE means the animation will reverse directions on each iteration.
 
     private int mRepeatMode = ;

    
The time interpolator to be used. The elapsed fraction of the animation will be passed through this interpolator to calculate the interpolated fraction, which is then used to calculate the animated values.
 
     private /*Time*/Interpolator mInterpolator = ;

    
The set of listeners to be sent events through the life of an animation.
 
     private ArrayList<AnimatorUpdateListenermUpdateListeners = null;

    
The property/value sets being animated.
 
     PropertyValuesHolder[] mValues;

    
A hashmap of the PropertyValuesHolder objects. This map is used to lookup animated values by property name during calls to getAnimatedValue(String).
 
Public constants
 

    
When the animation reaches the end and repeatCount is INFINITE or a positive value, the animation restarts from the beginning.
 
     public static final int RESTART = 1;
    
When the animation reaches the end and repeatCount is INFINITE or a positive value, the animation reverses direction on every iteration.
 
     public static final int REVERSE = 2;
    
This value used used with the setRepeatCount(int) property to repeat the animation indefinitely.
 
     public static final int INFINITE = -1;

    
Creates a new ValueAnimator object. This default constructor is primarily for use internally; the factory methods which take parameters are more generally useful.
 
     public ValueAnimator() {
     }

    
Constructs and returns a ValueAnimator that animates between int values. A single value implies that that value is the one being animated to. However, this is not typically useful in a ValueAnimator object because there is no way for the object to determine the starting value for the animation (unlike ObjectAnimator, which can derive that value from the target object and property being animated). Therefore, there should typically be two or more values.

Parameters:
values A set of values that the animation will animate between over time.
Returns:
A ValueAnimator object that is set up to animate between the given values.
 
     public static ValueAnimator ofInt(int... values) {
         ValueAnimator anim = new ValueAnimator();
         anim.setIntValues(values);
         return anim;
     }

    
Constructs and returns a ValueAnimator that animates between float values. A single value implies that that value is the one being animated to. However, this is not typically useful in a ValueAnimator object because there is no way for the object to determine the starting value for the animation (unlike ObjectAnimator, which can derive that value from the target object and property being animated). Therefore, there should typically be two or more values.

Parameters:
values A set of values that the animation will animate between over time.
Returns:
A ValueAnimator object that is set up to animate between the given values.
 
     public static ValueAnimator ofFloat(float... values) {
         ValueAnimator anim = new ValueAnimator();
         anim.setFloatValues(values);
         return anim;
     }

    
Constructs and returns a ValueAnimator that animates between the values specified in the PropertyValuesHolder objects.

Parameters:
values A set of PropertyValuesHolder objects whose values will be animated between over time.
Returns:
A ValueAnimator object that is set up to animate between the given values.
 
     public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values) {
         ValueAnimator anim = new ValueAnimator();
         anim.setValues(values);
         return anim;
     }
    
Constructs and returns a ValueAnimator that animates between Object values. A single value implies that that value is the one being animated to. However, this is not typically useful in a ValueAnimator object because there is no way for the object to determine the starting value for the animation (unlike ObjectAnimator, which can derive that value from the target object and property being animated). Therefore, there should typically be two or more values.

Since ValueAnimator does not know how to animate between arbitrary Objects, this factory method also takes a TypeEvaluator object that the ValueAnimator will use to perform that interpolation.

Parameters:
evaluator A TypeEvaluator that will be called on each animation frame to provide the ncessry interpolation between the Object values to derive the animated value.
values A set of values that the animation will animate between over time.
Returns:
A ValueAnimator object that is set up to animate between the given values.
 
     public static ValueAnimator ofObject(TypeEvaluator evaluatorObject... values) {
         ValueAnimator anim = new ValueAnimator();
         anim.setObjectValues(values);
         anim.setEvaluator(evaluator);
         return anim;
     }

    
Sets int values that will be animated between. A single value implies that that value is the one being animated to. However, this is not typically useful in a ValueAnimator object because there is no way for the object to determine the starting value for the animation (unlike ObjectAnimator, which can derive that value from the target object and property being animated). Therefore, there should typically be two or more values.

If there are already multiple sets of values defined for this ValueAnimator via more than one PropertyValuesHolder object, this method will set the values for the first of those objects.

Parameters:
values A set of values that the animation will animate between over time.
 
     public void setIntValues(int... values) {
         if (values == null || values.length == 0) {
             return;
         }
         if ( == null || . == 0) {
             setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofInt(""values)});
         } else {
             PropertyValuesHolder valuesHolder = [0];
             valuesHolder.setIntValues(values);
         }
         // New property/values/target should cause re-initialization prior to starting
          = false;
     }

    
Sets float values that will be animated between. A single value implies that that value is the one being animated to. However, this is not typically useful in a ValueAnimator object because there is no way for the object to determine the starting value for the animation (unlike ObjectAnimator, which can derive that value from the target object and property being animated). Therefore, there should typically be two or more values.

If there are already multiple sets of values defined for this ValueAnimator via more than one PropertyValuesHolder object, this method will set the values for the first of those objects.

Parameters:
values A set of values that the animation will animate between over time.
 
     public void setFloatValues(float... values) {
         if (values == null || values.length == 0) {
             return;
         }
         if ( == null || . == 0) {
             setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofFloat(""values)});
         } else {
             PropertyValuesHolder valuesHolder = [0];
             valuesHolder.setFloatValues(values);
         }
         // New property/values/target should cause re-initialization prior to starting
          = false;
     }

    
Sets the values to animate between for this animation. A single value implies that that value is the one being animated to. However, this is not typically useful in a ValueAnimator object because there is no way for the object to determine the starting value for the animation (unlike ObjectAnimator, which can derive that value from the target object and property being animated). Therefore, there should typically be two or more values.

If there are already multiple sets of values defined for this ValueAnimator via more than one PropertyValuesHolder object, this method will set the values for the first of those objects.

There should be a TypeEvaluator set on the ValueAnimator that knows how to interpolate between these value objects. ValueAnimator only knows how to interpolate between the primitive types specified in the other setValues() methods.

Parameters:
values The set of values to animate between.
 
     public void setObjectValues(Object... values) {
         if (values == null || values.length == 0) {
             return;
         }
         if ( == null || . == 0) {
             setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofObject("",
                     (TypeEvaluator)nullvalues)});
         } else {
             PropertyValuesHolder valuesHolder = [0];
             valuesHolder.setObjectValues(values);
         }
         // New property/values/target should cause re-initialization prior to starting
          = false;
     }

    
Sets the values, per property, being animated between. This function is called internally by the constructors of ValueAnimator that take a list of values. But an ValueAnimator can be constructed without values and this method can be called to set the values manually instead.

Parameters:
values The set of values, per property, being animated between.
 
     public void setValues(PropertyValuesHolder... values) {
         int numValues = values.length;
          = values;
          = new HashMap<StringPropertyValuesHolder>(numValues);
         for (int i = 0; i < numValues; ++i) {
             PropertyValuesHolder valuesHolder = values[i];
             .put(valuesHolder.getPropertyName(), valuesHolder);
         }
         // New property/values/target should cause re-initialization prior to starting
          = false;
     }

    
Returns the values that this ValueAnimator animates between. These values are stored in PropertyValuesHolder objects, even if the ValueAnimator was created with a simple list of value objects instead.

Returns:
PropertyValuesHolder[] An array of PropertyValuesHolder objects which hold the values, per property, that define the animation.
 
     public PropertyValuesHolder[] getValues() {
         return ;
     }

    
This function is called immediately before processing the first animation frame of an animation. If there is a nonzero startDelay, the function is called after that delay ends. It takes care of the final initialization steps for the animation.

Overrides of this method should call the superclass method to ensure that internal mechanisms for the animation are set up correctly.

 
     void initAnimation() {
         if (!) {
             int numValues = .;
             for (int i = 0; i < numValues; ++i) {
                 [i].init();
             }
              = true;
         }
     }


    
Sets the length of the animation. The default duration is 300 milliseconds.

Parameters:
duration The length of the animation, in milliseconds. This value cannot be negative.
Returns:
ValueAnimator The object called with setDuration(). This return value makes it easier to compose statements together that construct and then set the duration, as in ValueAnimator.ofInt(0, 10).setDuration(500).start().
 
     public ValueAnimator setDuration(long duration) {
         if (duration < 0) {
             throw new IllegalArgumentException("Animators cannot have negative duration: " +
                     duration);
         }
          = duration;
         return this;
     }

    
Gets the length of the animation. The default duration is 300 milliseconds.

Returns:
The length of the animation, in milliseconds.
 
     public long getDuration() {
         return ;
     }

    
Sets the position of the animation to the specified point in time. This time should be between 0 and the total duration of the animation, including any repetition. If the animation has not yet been started, then it will not advance forward after it is set to this time; it will simply set the time to this value and perform any appropriate actions based on that time. If the animation is already running, then setCurrentPlayTime() will set the current playing time to this value and continue playing from that point.

Parameters:
playTime The time, in milliseconds, to which the animation is advanced or rewound.
 
     public void setCurrentPlayTime(long playTime) {
         initAnimation();
         long currentTime = AnimationUtils.currentAnimationTimeMillis();
         if ( != ) {
              = playTime;
              = ;
         }
          = currentTime - playTime;
         animationFrame(currentTime);
     }

    
Gets the current position of the animation in time, which is equal to the current time minus the time that the animation started. An animation that is not yet started will return a value of zero.

Returns:
The current position in time of the animation.
 
     public long getCurrentPlayTime() {
         if (! ||  == ) {
             return 0;
         }
         return AnimationUtils.currentAnimationTimeMillis() - ;
     }

    
This custom, static handler handles the timing pulse that is shared by all active animations. This approach ensures that the setting of animation values will happen on the UI thread and that all animations will share the same times for calculating their values, which makes synchronizing animations possible.
 
     private static class AnimationHandler extends Handler {
        
There are only two messages that we care about: ANIMATION_START and ANIMATION_FRAME. The START message is sent when an animation's start() method is called. It cannot start synchronously when start() is called because the call may be on the wrong thread, and it would also not be synchronized with other animations because it would not start on a common timing pulse. So each animation sends a START message to the handler, which causes the handler to place the animation on the active animations queue and start processing frames for that animation. The FRAME message is the one that is sent over and over while there are any active animations to process.
 
         @Override
         public void handleMessage(Message msg) {
             boolean callAgain = true;
             ArrayList<ValueAnimatoranimations = .get();
             ArrayList<ValueAnimatordelayedAnims = .get();
             switch (msg.what) {
                 // TODO: should we avoid sending frame message when starting if we
                 // were already running?
                 case :
                     ArrayList<ValueAnimatorpendingAnimations = .get();
                     if (animations.size() > 0 || delayedAnims.size() > 0) {
                         callAgain = false;
                     }
                     // pendingAnims holds any animations that have requested to be started
                     // We're going to clear sPendingAnimations, but starting animation may
                     // cause more to be added to the pending list (for example, if one animation
                     // starting triggers another starting). So we loop until sPendingAnimations
                     // is empty.
                     while (pendingAnimations.size() > 0) {
                         ArrayList<ValueAnimatorpendingCopy =
                                 (ArrayList<ValueAnimator>) pendingAnimations.clone();
                         pendingAnimations.clear();
                         int count = pendingCopy.size();
                         for (int i = 0; i < count; ++i) {
                             ValueAnimator anim = pendingCopy.get(i);
                             // If the animation has a startDelay, place it on the delayed list
                             if (anim.mStartDelay == 0) {
                                 anim.startAnimation();
                             } else {
                                 delayedAnims.add(anim);
                             }
                         }
                     }
                     // fall through to process first frame of new animations
                 case :
                     // currentTime holds the common time for all animations processed
                     // during this frame
                     long currentTime = AnimationUtils.currentAnimationTimeMillis();
                     ArrayList<ValueAnimatorreadyAnims = .get();
                     ArrayList<ValueAnimatorendingAnims = .get();
 
                     // First, process animations currently sitting on the delayed queue, adding
                     // them to the active animations if they are ready
                     int numDelayedAnims = delayedAnims.size();
                     for (int i = 0; i < numDelayedAnims; ++i) {
                         ValueAnimator anim = delayedAnims.get(i);
                         if (anim.delayedAnimationFrame(currentTime)) {
                             readyAnims.add(anim);
                         }
                     }
                     int numReadyAnims = readyAnims.size();
                     if (numReadyAnims > 0) {
                         for (int i = 0; i < numReadyAnims; ++i) {
                             ValueAnimator anim = readyAnims.get(i);
                             anim.startAnimation();
                             anim.mRunning = true;
                             delayedAnims.remove(anim);
                         }
                         readyAnims.clear();
                     }
 
                     // Now process all active animations. The return value from animationFrame()
                     // tells the handler whether it should now be ended
                     int numAnims = animations.size();
                     int i = 0;
                     while (i < numAnims) {
                         ValueAnimator anim = animations.get(i);
                         if (anim.animationFrame(currentTime)) {
                             endingAnims.add(anim);
                         }
                         if (animations.size() == numAnims) {
                             ++i;
                         } else {
                             // An animation might be canceled or ended by client code
                             // during the animation frame. Check to see if this happened by
                             // seeing whether the current index is the same as it was before
                             // calling animationFrame(). Another approach would be to copy
                             // animations to a temporary list and process that list instead,
                             // but that entails garbage and processing overhead that would
                             // be nice to avoid.
                             --numAnims;
                             endingAnims.remove(anim);
                         }
                     }
                     if (endingAnims.size() > 0) {
                         for (i = 0; i < endingAnims.size(); ++i) {
                             endingAnims.get(i).endAnimation();
                         }
                         endingAnims.clear();
                     }
 
                     // If there are still active or delayed animations, call the handler again
                     // after the frameDelay
                     if (callAgain && (!animations.isEmpty() || !delayedAnims.isEmpty())) {
                         sendEmptyMessageDelayed(, Math.max(0,  -
                             (AnimationUtils.currentAnimationTimeMillis() - currentTime)));
                     }
                     break;
             }
         }
     }

    
The amount of time, in milliseconds, to delay starting the animation after start() is called.

Returns:
the number of milliseconds to delay running the animation
 
     public long getStartDelay() {
         return ;
     }

    
The amount of time, in milliseconds, to delay starting the animation after start() is called.

Parameters:
startDelay The amount of the delay, in milliseconds
 
     public void setStartDelay(long startDelay) {
         this. = startDelay;
     }

    
The amount of time, in milliseconds, between each frame of the animation. This is a requested time that the animation will attempt to honor, but the actual delay between frames may be different, depending on system load and capabilities. This is a static function because the same delay will be applied to all animations, since they are all run off of a single timing loop.

Returns:
the requested time between frames, in milliseconds
 
     public static long getFrameDelay() {
         return ;
     }

    
The amount of time, in milliseconds, between each frame of the animation. This is a requested time that the animation will attempt to honor, but the actual delay between frames may be different, depending on system load and capabilities. This is a static function because the same delay will be applied to all animations, since they are all run off of a single timing loop.

Parameters:
frameDelay the requested time between frames, in milliseconds
 
     public static void setFrameDelay(long frameDelay) {
          = frameDelay;
     }

    
The most recent value calculated by this ValueAnimator when there is just one property being animated. This value is only sensible while the animation is running. The main purpose for this read-only property is to retrieve the value from the ValueAnimator during a call to ValueAnimator.AnimatorUpdateListener.onAnimationUpdate(com.actionbarsherlock.internal.nineoldandroids.animation.ValueAnimator), which is called during each animation frame, immediately after the value is calculated.

Returns:
animatedValue The value most recently calculated by this ValueAnimator for the single property being animated. If there are several properties being animated (specified by several PropertyValuesHolder objects in the constructor), this function returns the animated value for the first of those objects.
 
     public Object getAnimatedValue() {
         if ( != null && . > 0) {
             return [0].getAnimatedValue();
         }
         // Shouldn't get here; should always have values unless ValueAnimator was set up wrong
         return null;
     }

    
The most recent value calculated by this ValueAnimator for propertyName. The main purpose for this read-only property is to retrieve the value from the ValueAnimator during a call to ValueAnimator.AnimatorUpdateListener.onAnimationUpdate(com.actionbarsherlock.internal.nineoldandroids.animation.ValueAnimator), which is called during each animation frame, immediately after the value is calculated.

Returns:
animatedValue The value most recently calculated for the named property by this ValueAnimator.
 
     public Object getAnimatedValue(String propertyName) {
         PropertyValuesHolder valuesHolder = .get(propertyName);
         if (valuesHolder != null) {
             return valuesHolder.getAnimatedValue();
         } else {
             // At least avoid crashing if called with bogus propertyName
             return null;
         }
     }

    
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 INFINITE, the repeat mode will be taken into account. The repeat count is 0 by default.

Parameters:
value the number of times the animation should be repeated
 
     public void setRepeatCount(int value) {
          = value;
     }
    
Defines how many times the animation should repeat. The default value is 0.

Returns:
the number of times the animation should repeat, or INFINITE
 
     public int getRepeatCount() {
         return ;
     }

    
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 INFINITE. Defaults to RESTART.

Parameters:
value RESTART or REVERSE
 
     public void setRepeatMode(int value) {
          = value;
     }

    
Defines what this animation should do when it reaches the end.

Returns:
either one of REVERSE or RESTART
 
     public int getRepeatMode() {
         return ;
     }

    
Adds a listener to the set of listeners that are sent update events through the life of an animation. This method is called on all listeners for every frame of the animation, after the values for the animation have been calculated.

Parameters:
listener the listener to be added to the current set of listeners for this animation.
 
     public void addUpdateListener(AnimatorUpdateListener listener) {
         if ( == null) {
              = new ArrayList<AnimatorUpdateListener>();
         }
         .add(listener);
     }

    
Removes all listeners from the set listening to frame updates for this animation.
 
     public void removeAllUpdateListeners() {
         if ( == null) {
             return;
         }
         .clear();
          = null;
     }

    
Removes a listener from the set listening to frame updates for this animation.

Parameters:
listener the listener to be removed from the current set of update listeners for this animation.
 
     public void removeUpdateListener(AnimatorUpdateListener listener) {
         if ( == null) {
             return;
         }
         .remove(listener);
         if (.size() == 0) {
              = null;
         }
     }


    
The time interpolator used in calculating the elapsed fraction of this animation. The interpolator determines whether the animation runs with linear or non-linear motion, such as acceleration and deceleration. The default value is android.view.animation.AccelerateDecelerateInterpolator

Parameters:
value the interpolator to be used by this animation. A value of null will result in linear interpolation.
 
     @Override
     public void setInterpolator(/*Time*/Interpolator value) {
         if (value != null) {
              = value;
         } else {
              = new LinearInterpolator();
         }
     }

    
Returns the timing interpolator that this ValueAnimator uses.

Returns:
The timing interpolator for this ValueAnimator.
 
     public /*Time*/Interpolator getInterpolator() {
         return ;
     }

    
The type evaluator to be used when calculating the animated values of this animation. The system will automatically assign a float or int evaluator based on the type of startValue and endValue in the constructor. But if these values are not one of these primitive types, or if different evaluation is desired (such as is necessary with int values that represent colors), a custom evaluator needs to be assigned. For example, when running an animation on color values, the ArgbEvaluator should be used to get correct RGB color interpolation.

If this ValueAnimator has only one set of values being animated between, this evaluator will be used for that set. If there are several sets of values being animated, which is the case if PropertyValuesHOlder objects were set on the ValueAnimator, then the evaluator is assigned just to the first PropertyValuesHolder object.

Parameters:
value the evaluator to be used this animation
 
     public void setEvaluator(TypeEvaluator value) {
         if (value != null &&  != null && . > 0) {
             [0].setEvaluator(value);
         }
     }

    
Start the animation playing. This version of start() takes a boolean flag that indicates whether the animation should play in reverse. The flag is usually false, but may be set to true if called from the reverse() method.

The animation started by calling this method will be run on the thread that called this method. This thread should have a Looper on it (a runtime exception will be thrown if this is not the case). Also, if the animation will animate properties of objects in the view hierarchy, then the calling thread should be the UI thread for that view hierarchy.

Parameters:
playBackwards Whether the ValueAnimator should start playing in reverse.
 
     private void start(boolean playBackwards) {
         if (Looper.myLooper() == null) {
             throw new AndroidRuntimeException("Animators may only be run on Looper threads");
         }
          = playBackwards;
          = 0;
          = ;
          = true;
          = false;
         .get().add(this);
         if ( == 0) {
             // This sets the initial value of the animation, prior to actually starting it running
             setCurrentPlayTime(getCurrentPlayTime());
              = ;
              = true;
 
             if ( != null) {
                 ArrayList<AnimatorListenertmpListeners =
                         (ArrayList<AnimatorListener>) .clone();
                 int numListeners = tmpListeners.size();
                 for (int i = 0; i < numListeners; ++i) {
                     tmpListeners.get(i).onAnimationStart(this);
                 }
             }
         }
         AnimationHandler animationHandler = .get();
         if (animationHandler == null) {
             animationHandler = new AnimationHandler();
             .set(animationHandler);
         }
         animationHandler.sendEmptyMessage();
     }
 
     @Override
     public void start() {
         start(false);
     }
 
     @Override
     public void cancel() {
         // Only cancel if the animation is actually running or has been started and is about
         // to run
         if ( !=  || .get().contains(this) ||
                 .get().contains(this)) {
             // Only notify listeners if the animator has actually started
             if ( &&  != null) {
                 ArrayList<AnimatorListenertmpListeners =
                         (ArrayList<AnimatorListener>) .clone();
                 for (AnimatorListener listener : tmpListeners) {
                     listener.onAnimationCancel(this);
                 }
             }
             endAnimation();
         }
     }
 
     @Override
     public void end() {
         if (!.get().contains(this) && !.get().contains(this)) {
             // Special case if the animation has not yet started; get it ready for ending
              = false;
             startAnimation();
         } else if (!) {
             initAnimation();
         }
         // The final value set on the target varies, depending on whether the animation
         // was supposed to repeat an odd number of times
         if ( > 0 && ( & 0x01) == 1) {
             animateValue(0f);
         } else {
             animateValue(1f);
         }
         endAnimation();
     }
 
     @Override
     public boolean isRunning() {
         return ( ==  || );
     }
 
     @Override
     public boolean isStarted() {
         return ;
    }

    
Plays the ValueAnimator in reverse. If the animation is already running, it will stop itself and play backwards from the point reached when reverse was called. If the animation is not currently running, then it will start from the end and play backwards. This behavior is only set for the current animation; future playing of the animation will use the default behavior of playing forward.
    public void reverse() {
        if ( == ) {
            long currentTime = AnimationUtils.currentAnimationTimeMillis();
            long currentPlayTime = currentTime - ;
            long timeLeft =  - currentPlayTime;
             = currentTime - timeLeft;
        } else {
            start(true);
        }
    }

    
Called internally to end an animation by removing it from the animations list. Must be called on the UI thread.
    private void endAnimation() {
        .get().remove(this);
        .get().remove(this);
        .get().remove(this);
         = ;
        if ( &&  != null) {
            ArrayList<AnimatorListenertmpListeners =
                    (ArrayList<AnimatorListener>) .clone();
            int numListeners = tmpListeners.size();
            for (int i = 0; i < numListeners; ++i) {
                tmpListeners.get(i).onAnimationEnd(this);
            }
        }
         = false;
         = false;
    }

    
Called internally to start an animation by adding it to the active animations list. Must be called on the UI thread.
    private void startAnimation() {
        initAnimation();
        .get().add(this);
        if ( > 0 &&  != null) {
            // Listeners were already notified in start() if startDelay is 0; this is
            // just for delayed animations
            ArrayList<AnimatorListenertmpListeners =
                    (ArrayList<AnimatorListener>) .clone();
            int numListeners = tmpListeners.size();
            for (int i = 0; i < numListeners; ++i) {
                tmpListeners.get(i).onAnimationStart(this);
            }
        }
    }

    
Internal function called to process an animation frame on an animation that is currently sleeping through its startDelay phase. The return value indicates whether it should be woken up and put on the active animations queue.

Parameters:
currentTime The current animation time, used to calculate whether the animation has exceeded its startDelay and should be started.
Returns:
True if the animation's startDelay has been exceeded and the animation should be added to the set of active animations.
    private boolean delayedAnimationFrame(long currentTime) {
        if (!) {
             = true;
             = currentTime;
        } else {
            long deltaTime = currentTime - ;
            if (deltaTime > ) {
                // startDelay ended - start the anim and record the
                // mStartTime appropriately
                 = currentTime - (deltaTime - );
                 = ;
                return true;
            }
        }
        return false;
    }

    
This internal function processes a single animation frame for a given animation. The currentTime parameter is the timing pulse sent by the handler, used to calculate the elapsed duration, and therefore the elapsed fraction, of the animation. The return value indicates whether the animation should be ended (which happens when the elapsed time of the animation exceeds the animation's duration, including the repeatCount).

Parameters:
currentTime The current time, as tracked by the static timing handler
Returns:
true if the animation's duration, including any repetitions due to repeatCount has been exceeded and the animation should be ended.
    boolean animationFrame(long currentTime) {
        boolean done = false;
        if ( == ) {
             = ;
            if ( < 0) {
                 = currentTime;
            } else {
                 = currentTime - ;
                // Now that we're playing, reset the seek time
                 = -1;
            }
        }
        switch () {
        case :
        case :
            float fraction =  > 0 ? (float)(currentTime - ) /  : 1f;
            if (fraction >= 1f) {
                if ( <  ||  == ) {
                    // Time to repeat
                    if ( != null) {
                        int numListeners = .size();
                        for (int i = 0; i < numListeners; ++i) {
                            .get(i).onAnimationRepeat(this);
                        }
                    }
                    if ( == ) {
                         =  ? false : true;
                    }
                     += (int)fraction;
                    fraction = fraction % 1f;
                     += ;
                } else {
                    done = true;
                    fraction = Math.min(fraction, 1.0f);
                }
            }
            if () {
                fraction = 1f - fraction;
            }
            animateValue(fraction);
            break;
        }
        return done;
    }

    
Returns the current animation fraction, which is the elapsed/interpolated fraction used in the most recent frame update on the animation.

Returns:
Elapsed/interpolated fraction of the animation.
    public float getAnimatedFraction() {
        return ;
    }

    
This method is called with the elapsed fraction of the animation during every animation frame. This function turns the elapsed fraction into an interpolated fraction and then into an animated value (from the evaluator. The function is called mostly during animation updates, but it is also called when the end() function is called, to set the final value on the property.

Overrides of this method must call the superclass to perform the calculation of the animated value.

Parameters:
fraction The elapsed fraction of the animation.
    void animateValue(float fraction) {
        fraction = .getInterpolation(fraction);
         = fraction;
        int numValues = .;
        for (int i = 0; i < numValues; ++i) {
            [i].calculateValue(fraction);
        }
        if ( != null) {
            int numListeners = .size();
            for (int i = 0; i < numListeners; ++i) {
                .get(i).onAnimationUpdate(this);
            }
        }
    }
    @Override
    public ValueAnimator clone() {
        final ValueAnimator anim = (ValueAnimatorsuper.clone();
        if ( != null) {
            ArrayList<AnimatorUpdateListeneroldListeners = ;
            anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>();
            int numListeners = oldListeners.size();
            for (int i = 0; i < numListeners; ++i) {
                anim.mUpdateListeners.add(oldListeners.get(i));
            }
        }
        anim.mSeekTime = -1;
        anim.mPlayingBackwards = false;
        anim.mCurrentIteration = 0;
        anim.mInitialized = false;
        anim.mPlayingState = ;
        anim.mStartedDelay = false;
        PropertyValuesHolder[] oldValues = ;
        if (oldValues != null) {
            int numValues = oldValues.length;
            anim.mValues = new PropertyValuesHolder[numValues];
            anim.mValuesMap = new HashMap<StringPropertyValuesHolder>(numValues);
            for (int i = 0; i < numValues; ++i) {
                PropertyValuesHolder newValuesHolder = oldValues[i].clone();
                anim.mValues[i] = newValuesHolder;
                anim.mValuesMap.put(newValuesHolder.getPropertyName(), newValuesHolder);
            }
        }
        return anim;
    }

    
Implementors of this interface can add themselves as update listeners to an ValueAnimator instance to receive callbacks on every animation frame, after the current frame's values have been calculated for that ValueAnimator.
    public static interface AnimatorUpdateListener {
        

Notifies the occurrence of another frame of the animation.

Parameters:
animation The animation which was repeated.
        void onAnimationUpdate(ValueAnimator animation);
    }

    
Return the number of animations currently running. Used by StrictMode internally to annotate violations. Only called on the main thread.

Hide:
    public static int getCurrentAnimationsCount() {
        return .get().size();
    }

    
Clear all animations on this thread, without canceling or ending them. This should be used with caution.

Hide:
    public static void clearAllAnimations() {
        .get().clear();
        .get().clear();
        .get().clear();
    }
    @Override
    public String toString() {
        String returnVal = "ValueAnimator@" + Integer.toHexString(hashCode());
        if ( != null) {
            for (int i = 0; i < .; ++i) {
                returnVal += "\n    " + [i].toString();
            }
        }
        return returnVal;
    }
New to GrepCode? Check out our FAQ X