Home | History | Annotate | Download | only in view
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.view;
     18 
     19 import android.animation.Animator;
     20 import android.animation.TimeInterpolator;
     21 import android.animation.ValueAnimator;
     22 
     23 import java.util.ArrayList;
     24 import java.util.HashMap;
     25 import java.util.Set;
     26 
     27 /**
     28  * This class enables automatic and optimized animation of select properties on View objects.
     29  * If only one or two properties on a View object are being animated, then using an
     30  * {@link android.animation.ObjectAnimator} is fine; the property setters called by ObjectAnimator
     31  * are well equipped to do the right thing to set the property and invalidate the view
     32  * appropriately. But if several properties are animated simultaneously, or if you just want a
     33  * more convenient syntax to animate a specific property, then ViewPropertyAnimator might be
     34  * more well-suited to the task.
     35  *
     36  * <p>This class may provide better performance for several simultaneous animations, because
     37  * it will optimize invalidate calls to take place only once for several properties instead of each
     38  * animated property independently causing its own invalidation. Also, the syntax of using this
     39  * class could be easier to use because the caller need only tell the View object which
     40  * property to animate, and the value to animate either to or by, and this class handles the
     41  * details of configuring the underlying Animator class and starting it.</p>
     42  *
     43  * <p>This class is not constructed by the caller, but rather by the View whose properties
     44  * it will animate. Calls to {@link android.view.View#animate()} will return a reference
     45  * to the appropriate ViewPropertyAnimator object for that View.</p>
     46  *
     47  */
     48 public class ViewPropertyAnimator {
     49 
     50     /**
     51      * The View whose properties are being animated by this class. This is set at
     52      * construction time.
     53      */
     54     final View mView;
     55 
     56     /**
     57      * The duration of the underlying Animator object. By default, we don't set the duration
     58      * on the Animator and just use its default duration. If the duration is ever set on this
     59      * Animator, then we use the duration that it was set to.
     60      */
     61     private long mDuration;
     62 
     63     /**
     64      * A flag indicating whether the duration has been set on this object. If not, we don't set
     65      * the duration on the underlying Animator, but instead just use its default duration.
     66      */
     67     private boolean mDurationSet = false;
     68 
     69     /**
     70      * The startDelay of the underlying Animator object. By default, we don't set the startDelay
     71      * on the Animator and just use its default startDelay. If the startDelay is ever set on this
     72      * Animator, then we use the startDelay that it was set to.
     73      */
     74     private long mStartDelay = 0;
     75 
     76     /**
     77      * A flag indicating whether the startDelay has been set on this object. If not, we don't set
     78      * the startDelay on the underlying Animator, but instead just use its default startDelay.
     79      */
     80     private boolean mStartDelaySet = false;
     81 
     82     /**
     83      * The interpolator of the underlying Animator object. By default, we don't set the interpolator
     84      * on the Animator and just use its default interpolator. If the interpolator is ever set on
     85      * this Animator, then we use the interpolator that it was set to.
     86      */
     87     private TimeInterpolator mInterpolator;
     88 
     89     /**
     90      * A flag indicating whether the interpolator has been set on this object. If not, we don't set
     91      * the interpolator on the underlying Animator, but instead just use its default interpolator.
     92      */
     93     private boolean mInterpolatorSet = false;
     94 
     95     /**
     96      * Listener for the lifecycle events of the underlying ValueAnimator object.
     97      */
     98     private Animator.AnimatorListener mListener = null;
     99 
    100     /**
    101      * Listener for the update events of the underlying ValueAnimator object.
    102      */
    103     private ValueAnimator.AnimatorUpdateListener mUpdateListener = null;
    104 
    105     /**
    106      * A lazily-created ValueAnimator used in order to get some default animator properties
    107      * (duration, start delay, interpolator, etc.).
    108      */
    109     private ValueAnimator mTempValueAnimator;
    110 
    111     /**
    112      * A RenderThread-driven backend that may intercept startAnimation
    113      */
    114     private ViewPropertyAnimatorRT mRTBackend;
    115 
    116     /**
    117      * This listener is the mechanism by which the underlying Animator causes changes to the
    118      * properties currently being animated, as well as the cleanup after an animation is
    119      * complete.
    120      */
    121     private AnimatorEventListener mAnimatorEventListener = new AnimatorEventListener();
    122 
    123     /**
    124      * This list holds the properties that have been asked to animate. We allow the caller to
    125      * request several animations prior to actually starting the underlying animator. This
    126      * enables us to run one single animator to handle several properties in parallel. Each
    127      * property is tossed onto the pending list until the animation actually starts (which is
    128      * done by posting it onto mView), at which time the pending list is cleared and the properties
    129      * on that list are added to the list of properties associated with that animator.
    130      */
    131     ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();
    132     private Runnable mPendingSetupAction;
    133     private Runnable mPendingCleanupAction;
    134     private Runnable mPendingOnStartAction;
    135     private Runnable mPendingOnEndAction;
    136 
    137     /**
    138      * Constants used to associate a property being requested and the mechanism used to set
    139      * the property (this class calls directly into View to set the properties in question).
    140      */
    141     static final int NONE           = 0x0000;
    142     static final int TRANSLATION_X  = 0x0001;
    143     static final int TRANSLATION_Y  = 0x0002;
    144     static final int TRANSLATION_Z  = 0x0004;
    145     static final int SCALE_X        = 0x0008;
    146     static final int SCALE_Y        = 0x0010;
    147     static final int ROTATION       = 0x0020;
    148     static final int ROTATION_X     = 0x0040;
    149     static final int ROTATION_Y     = 0x0080;
    150     static final int X              = 0x0100;
    151     static final int Y              = 0x0200;
    152     static final int Z              = 0x0400;
    153     static final int ALPHA          = 0x0800;
    154 
    155     private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | TRANSLATION_Z |
    156             SCALE_X | SCALE_Y | ROTATION | ROTATION_X | ROTATION_Y | X | Y | Z;
    157 
    158     /**
    159      * The mechanism by which the user can request several properties that are then animated
    160      * together works by posting this Runnable to start the underlying Animator. Every time
    161      * a property animation is requested, we cancel any previous postings of the Runnable
    162      * and re-post it. This means that we will only ever run the Runnable (and thus start the
    163      * underlying animator) after the caller is done setting the properties that should be
    164      * animated together.
    165      */
    166     private Runnable mAnimationStarter = new Runnable() {
    167         @Override
    168         public void run() {
    169             startAnimation();
    170         }
    171     };
    172 
    173     /**
    174      * This class holds information about the overall animation being run on the set of
    175      * properties. The mask describes which properties are being animated and the
    176      * values holder is the list of all property/value objects.
    177      */
    178     private static class PropertyBundle {
    179         int mPropertyMask;
    180         ArrayList<NameValuesHolder> mNameValuesHolder;
    181 
    182         PropertyBundle(int propertyMask, ArrayList<NameValuesHolder> nameValuesHolder) {
    183             mPropertyMask = propertyMask;
    184             mNameValuesHolder = nameValuesHolder;
    185         }
    186 
    187         /**
    188          * Removes the given property from being animated as a part of this
    189          * PropertyBundle. If the property was a part of this bundle, it returns
    190          * true to indicate that it was, in fact, canceled. This is an indication
    191          * to the caller that a cancellation actually occurred.
    192          *
    193          * @param propertyConstant The property whose cancellation is requested.
    194          * @return true if the given property is a part of this bundle and if it
    195          * has therefore been canceled.
    196          */
    197         boolean cancel(int propertyConstant) {
    198             if ((mPropertyMask & propertyConstant) != 0 && mNameValuesHolder != null) {
    199                 int count = mNameValuesHolder.size();
    200                 for (int i = 0; i < count; ++i) {
    201                     NameValuesHolder nameValuesHolder = mNameValuesHolder.get(i);
    202                     if (nameValuesHolder.mNameConstant == propertyConstant) {
    203                         mNameValuesHolder.remove(i);
    204                         mPropertyMask &= ~propertyConstant;
    205                         return true;
    206                     }
    207                 }
    208             }
    209             return false;
    210         }
    211     }
    212 
    213     /**
    214      * This list tracks the list of properties being animated by any particular animator.
    215      * In most situations, there would only ever be one animator running at a time. But it is
    216      * possible to request some properties to animate together, then while those properties
    217      * are animating, to request some other properties to animate together. The way that
    218      * works is by having this map associate the group of properties being animated with the
    219      * animator handling the animation. On every update event for an Animator, we ask the
    220      * map for the associated properties and set them accordingly.
    221      */
    222     private HashMap<Animator, PropertyBundle> mAnimatorMap =
    223             new HashMap<Animator, PropertyBundle>();
    224     private HashMap<Animator, Runnable> mAnimatorSetupMap;
    225     private HashMap<Animator, Runnable> mAnimatorCleanupMap;
    226     private HashMap<Animator, Runnable> mAnimatorOnStartMap;
    227     private HashMap<Animator, Runnable> mAnimatorOnEndMap;
    228 
    229     /**
    230      * This is the information we need to set each property during the animation.
    231      * mNameConstant is used to set the appropriate field in View, and the from/delta
    232      * values are used to calculate the animated value for a given animation fraction
    233      * during the animation.
    234      */
    235     static class NameValuesHolder {
    236         int mNameConstant;
    237         float mFromValue;
    238         float mDeltaValue;
    239         NameValuesHolder(int nameConstant, float fromValue, float deltaValue) {
    240             mNameConstant = nameConstant;
    241             mFromValue = fromValue;
    242             mDeltaValue = deltaValue;
    243         }
    244     }
    245 
    246     /**
    247      * Constructor, called by View. This is private by design, as the user should only
    248      * get a ViewPropertyAnimator by calling View.animate().
    249      *
    250      * @param view The View associated with this ViewPropertyAnimator
    251      */
    252     ViewPropertyAnimator(View view) {
    253         mView = view;
    254         view.ensureTransformationInfo();
    255     }
    256 
    257     /**
    258      * Sets the duration for the underlying animator that animates the requested properties.
    259      * By default, the animator uses the default value for ValueAnimator. Calling this method
    260      * will cause the declared value to be used instead.
    261      * @param duration The length of ensuing property animations, in milliseconds. The value
    262      * cannot be negative.
    263      * @return This object, allowing calls to methods in this class to be chained.
    264      */
    265     public ViewPropertyAnimator setDuration(long duration) {
    266         if (duration < 0) {
    267             throw new IllegalArgumentException("Animators cannot have negative duration: " +
    268                     duration);
    269         }
    270         mDurationSet = true;
    271         mDuration = duration;
    272         return this;
    273     }
    274 
    275     /**
    276      * Returns the current duration of property animations. If the duration was set on this
    277      * object, that value is returned. Otherwise, the default value of the underlying Animator
    278      * is returned.
    279      *
    280      * @see #setDuration(long)
    281      * @return The duration of animations, in milliseconds.
    282      */
    283     public long getDuration() {
    284         if (mDurationSet) {
    285             return mDuration;
    286         } else {
    287             // Just return the default from ValueAnimator, since that's what we'd get if
    288             // the value has not been set otherwise
    289             if (mTempValueAnimator == null) {
    290                 mTempValueAnimator = new ValueAnimator();
    291             }
    292             return mTempValueAnimator.getDuration();
    293         }
    294     }
    295 
    296     /**
    297      * Returns the current startDelay of property animations. If the startDelay was set on this
    298      * object, that value is returned. Otherwise, the default value of the underlying Animator
    299      * is returned.
    300      *
    301      * @see #setStartDelay(long)
    302      * @return The startDelay of animations, in milliseconds.
    303      */
    304     public long getStartDelay() {
    305         if (mStartDelaySet) {
    306             return mStartDelay;
    307         } else {
    308             // Just return the default from ValueAnimator (0), since that's what we'd get if
    309             // the value has not been set otherwise
    310             return 0;
    311         }
    312     }
    313 
    314     /**
    315      * Sets the startDelay for the underlying animator that animates the requested properties.
    316      * By default, the animator uses the default value for ValueAnimator. Calling this method
    317      * will cause the declared value to be used instead.
    318      * @param startDelay The delay of ensuing property animations, in milliseconds. The value
    319      * cannot be negative.
    320      * @return This object, allowing calls to methods in this class to be chained.
    321      */
    322     public ViewPropertyAnimator setStartDelay(long startDelay) {
    323         if (startDelay < 0) {
    324             throw new IllegalArgumentException("Animators cannot have negative start " +
    325                 "delay: " + startDelay);
    326         }
    327         mStartDelaySet = true;
    328         mStartDelay = startDelay;
    329         return this;
    330     }
    331 
    332     /**
    333      * Sets the interpolator for the underlying animator that animates the requested properties.
    334      * By default, the animator uses the default interpolator for ValueAnimator. Calling this method
    335      * will cause the declared object to be used instead.
    336      *
    337      * @param interpolator The TimeInterpolator to be used for ensuing property animations. A value
    338      * of <code>null</code> will result in linear interpolation.
    339      * @return This object, allowing calls to methods in this class to be chained.
    340      */
    341     public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) {
    342         mInterpolatorSet = true;
    343         mInterpolator = interpolator;
    344         return this;
    345     }
    346 
    347     /**
    348      * Returns the timing interpolator that this animation uses.
    349      *
    350      * @return The timing interpolator for this animation.
    351      */
    352     public TimeInterpolator getInterpolator() {
    353         if (mInterpolatorSet) {
    354             return mInterpolator;
    355         } else {
    356             // Just return the default from ValueAnimator, since that's what we'd get if
    357             // the value has not been set otherwise
    358             if (mTempValueAnimator == null) {
    359                 mTempValueAnimator = new ValueAnimator();
    360             }
    361             return mTempValueAnimator.getInterpolator();
    362         }
    363     }
    364 
    365     /**
    366      * Sets a listener for events in the underlying Animators that run the property
    367      * animations.
    368      *
    369      * @see Animator.AnimatorListener
    370      *
    371      * @param listener The listener to be called with AnimatorListener events. A value of
    372      * <code>null</code> removes any existing listener.
    373      * @return This object, allowing calls to methods in this class to be chained.
    374      */
    375     public ViewPropertyAnimator setListener(Animator.AnimatorListener listener) {
    376         mListener = listener;
    377         return this;
    378     }
    379 
    380     Animator.AnimatorListener getListener() {
    381         return mListener;
    382     }
    383 
    384     /**
    385      * Sets a listener for update events in the underlying ValueAnimator that runs
    386      * the property animations. Note that the underlying animator is animating between
    387      * 0 and 1 (these values are then turned into the actual property values internally
    388      * by ViewPropertyAnimator). So the animator cannot give information on the current
    389      * values of the properties being animated by this ViewPropertyAnimator, although
    390      * the view object itself can be queried to get the current values.
    391      *
    392      * @see android.animation.ValueAnimator.AnimatorUpdateListener
    393      *
    394      * @param listener The listener to be called with update events. A value of
    395      * <code>null</code> removes any existing listener.
    396      * @return This object, allowing calls to methods in this class to be chained.
    397      */
    398     public ViewPropertyAnimator setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) {
    399         mUpdateListener = listener;
    400         return this;
    401     }
    402 
    403     ValueAnimator.AnimatorUpdateListener getUpdateListener() {
    404         return mUpdateListener;
    405     }
    406 
    407     /**
    408      * Starts the currently pending property animations immediately. Calling <code>start()</code>
    409      * is optional because all animations start automatically at the next opportunity. However,
    410      * if the animations are needed to start immediately and synchronously (not at the time when
    411      * the next event is processed by the hierarchy, which is when the animations would begin
    412      * otherwise), then this method can be used.
    413      */
    414     public void start() {
    415         mView.removeCallbacks(mAnimationStarter);
    416         startAnimation();
    417     }
    418 
    419     /**
    420      * Cancels all property animations that are currently running or pending.
    421      */
    422     public void cancel() {
    423         if (mAnimatorMap.size() > 0) {
    424             HashMap<Animator, PropertyBundle> mAnimatorMapCopy =
    425                     (HashMap<Animator, PropertyBundle>)mAnimatorMap.clone();
    426             Set<Animator> animatorSet = mAnimatorMapCopy.keySet();
    427             for (Animator runningAnim : animatorSet) {
    428                 runningAnim.cancel();
    429             }
    430         }
    431         mPendingAnimations.clear();
    432         mPendingSetupAction = null;
    433         mPendingCleanupAction = null;
    434         mPendingOnStartAction = null;
    435         mPendingOnEndAction = null;
    436         mView.removeCallbacks(mAnimationStarter);
    437         if (mRTBackend != null) {
    438             mRTBackend.cancelAll();
    439         }
    440     }
    441 
    442     /**
    443      * This method will cause the View's <code>x</code> property to be animated to the
    444      * specified value. Animations already running on the property will be canceled.
    445      *
    446      * @param value The value to be animated to.
    447      * @see View#setX(float)
    448      * @return This object, allowing calls to methods in this class to be chained.
    449      */
    450     public ViewPropertyAnimator x(float value) {
    451         animateProperty(X, value);
    452         return this;
    453     }
    454 
    455     /**
    456      * This method will cause the View's <code>x</code> property to be animated by the
    457      * specified value. Animations already running on the property will be canceled.
    458      *
    459      * @param value The amount to be animated by, as an offset from the current value.
    460      * @see View#setX(float)
    461      * @return This object, allowing calls to methods in this class to be chained.
    462      */
    463     public ViewPropertyAnimator xBy(float value) {
    464         animatePropertyBy(X, value);
    465         return this;
    466     }
    467 
    468     /**
    469      * This method will cause the View's <code>y</code> property to be animated to the
    470      * specified value. Animations already running on the property will be canceled.
    471      *
    472      * @param value The value to be animated to.
    473      * @see View#setY(float)
    474      * @return This object, allowing calls to methods in this class to be chained.
    475      */
    476     public ViewPropertyAnimator y(float value) {
    477         animateProperty(Y, value);
    478         return this;
    479     }
    480 
    481     /**
    482      * This method will cause the View's <code>y</code> property to be animated by the
    483      * specified value. Animations already running on the property will be canceled.
    484      *
    485      * @param value The amount to be animated by, as an offset from the current value.
    486      * @see View#setY(float)
    487      * @return This object, allowing calls to methods in this class to be chained.
    488      */
    489     public ViewPropertyAnimator yBy(float value) {
    490         animatePropertyBy(Y, value);
    491         return this;
    492     }
    493 
    494     /**
    495      * This method will cause the View's <code>z</code> property to be animated to the
    496      * specified value. Animations already running on the property will be canceled.
    497      *
    498      * @param value The value to be animated to.
    499      * @see View#setZ(float)
    500      * @return This object, allowing calls to methods in this class to be chained.
    501      */
    502     public ViewPropertyAnimator z(float value) {
    503         animateProperty(Z, value);
    504         return this;
    505     }
    506 
    507     /**
    508      * This method will cause the View's <code>z</code> property to be animated by the
    509      * specified value. Animations already running on the property will be canceled.
    510      *
    511      * @param value The amount to be animated by, as an offset from the current value.
    512      * @see View#setZ(float)
    513      * @return This object, allowing calls to methods in this class to be chained.
    514      */
    515     public ViewPropertyAnimator zBy(float value) {
    516         animatePropertyBy(Z, value);
    517         return this;
    518     }
    519 
    520     /**
    521      * This method will cause the View's <code>rotation</code> property to be animated to the
    522      * specified value. Animations already running on the property will be canceled.
    523      *
    524      * @param value The value to be animated to.
    525      * @see View#setRotation(float)
    526      * @return This object, allowing calls to methods in this class to be chained.
    527      */
    528     public ViewPropertyAnimator rotation(float value) {
    529         animateProperty(ROTATION, value);
    530         return this;
    531     }
    532 
    533     /**
    534      * This method will cause the View's <code>rotation</code> property to be animated by the
    535      * specified value. Animations already running on the property will be canceled.
    536      *
    537      * @param value The amount to be animated by, as an offset from the current value.
    538      * @see View#setRotation(float)
    539      * @return This object, allowing calls to methods in this class to be chained.
    540      */
    541     public ViewPropertyAnimator rotationBy(float value) {
    542         animatePropertyBy(ROTATION, value);
    543         return this;
    544     }
    545 
    546     /**
    547      * This method will cause the View's <code>rotationX</code> property to be animated to the
    548      * specified value. Animations already running on the property will be canceled.
    549      *
    550      * @param value The value to be animated to.
    551      * @see View#setRotationX(float)
    552      * @return This object, allowing calls to methods in this class to be chained.
    553      */
    554     public ViewPropertyAnimator rotationX(float value) {
    555         animateProperty(ROTATION_X, value);
    556         return this;
    557     }
    558 
    559     /**
    560      * This method will cause the View's <code>rotationX</code> property to be animated by the
    561      * specified value. Animations already running on the property will be canceled.
    562      *
    563      * @param value The amount to be animated by, as an offset from the current value.
    564      * @see View#setRotationX(float)
    565      * @return This object, allowing calls to methods in this class to be chained.
    566      */
    567     public ViewPropertyAnimator rotationXBy(float value) {
    568         animatePropertyBy(ROTATION_X, value);
    569         return this;
    570     }
    571 
    572     /**
    573      * This method will cause the View's <code>rotationY</code> property to be animated to the
    574      * specified value. Animations already running on the property will be canceled.
    575      *
    576      * @param value The value to be animated to.
    577      * @see View#setRotationY(float)
    578      * @return This object, allowing calls to methods in this class to be chained.
    579      */
    580     public ViewPropertyAnimator rotationY(float value) {
    581         animateProperty(ROTATION_Y, value);
    582         return this;
    583     }
    584 
    585     /**
    586      * This method will cause the View's <code>rotationY</code> property to be animated by the
    587      * specified value. Animations already running on the property will be canceled.
    588      *
    589      * @param value The amount to be animated by, as an offset from the current value.
    590      * @see View#setRotationY(float)
    591      * @return This object, allowing calls to methods in this class to be chained.
    592      */
    593     public ViewPropertyAnimator rotationYBy(float value) {
    594         animatePropertyBy(ROTATION_Y, value);
    595         return this;
    596     }
    597 
    598     /**
    599      * This method will cause the View's <code>translationX</code> property to be animated to the
    600      * specified value. Animations already running on the property will be canceled.
    601      *
    602      * @param value The value to be animated to.
    603      * @see View#setTranslationX(float)
    604      * @return This object, allowing calls to methods in this class to be chained.
    605      */
    606     public ViewPropertyAnimator translationX(float value) {
    607         animateProperty(TRANSLATION_X, value);
    608         return this;
    609     }
    610 
    611     /**
    612      * This method will cause the View's <code>translationX</code> property to be animated by the
    613      * specified value. Animations already running on the property will be canceled.
    614      *
    615      * @param value The amount to be animated by, as an offset from the current value.
    616      * @see View#setTranslationX(float)
    617      * @return This object, allowing calls to methods in this class to be chained.
    618      */
    619     public ViewPropertyAnimator translationXBy(float value) {
    620         animatePropertyBy(TRANSLATION_X, value);
    621         return this;
    622     }
    623 
    624     /**
    625      * This method will cause the View's <code>translationY</code> property to be animated to the
    626      * specified value. Animations already running on the property will be canceled.
    627      *
    628      * @param value The value to be animated to.
    629      * @see View#setTranslationY(float)
    630      * @return This object, allowing calls to methods in this class to be chained.
    631      */
    632     public ViewPropertyAnimator translationY(float value) {
    633         animateProperty(TRANSLATION_Y, value);
    634         return this;
    635     }
    636 
    637     /**
    638      * This method will cause the View's <code>translationY</code> property to be animated by the
    639      * specified value. Animations already running on the property will be canceled.
    640      *
    641      * @param value The amount to be animated by, as an offset from the current value.
    642      * @see View#setTranslationY(float)
    643      * @return This object, allowing calls to methods in this class to be chained.
    644      */
    645     public ViewPropertyAnimator translationYBy(float value) {
    646         animatePropertyBy(TRANSLATION_Y, value);
    647         return this;
    648     }
    649 
    650     /**
    651      * This method will cause the View's <code>translationZ</code> property to be animated to the
    652      * specified value. Animations already running on the property will be canceled.
    653      *
    654      * @param value The value to be animated to.
    655      * @see View#setTranslationZ(float)
    656      * @return This object, allowing calls to methods in this class to be chained.
    657      */
    658     public ViewPropertyAnimator translationZ(float value) {
    659         animateProperty(TRANSLATION_Z, value);
    660         return this;
    661     }
    662 
    663     /**
    664      * This method will cause the View's <code>translationZ</code> property to be animated by the
    665      * specified value. Animations already running on the property will be canceled.
    666      *
    667      * @param value The amount to be animated by, as an offset from the current value.
    668      * @see View#setTranslationZ(float)
    669      * @return This object, allowing calls to methods in this class to be chained.
    670      */
    671     public ViewPropertyAnimator translationZBy(float value) {
    672         animatePropertyBy(TRANSLATION_Z, value);
    673         return this;
    674     }
    675     /**
    676      * This method will cause the View's <code>scaleX</code> property to be animated to the
    677      * specified value. Animations already running on the property will be canceled.
    678      *
    679      * @param value The value to be animated to.
    680      * @see View#setScaleX(float)
    681      * @return This object, allowing calls to methods in this class to be chained.
    682      */
    683     public ViewPropertyAnimator scaleX(float value) {
    684         animateProperty(SCALE_X, value);
    685         return this;
    686     }
    687 
    688     /**
    689      * This method will cause the View's <code>scaleX</code> property to be animated by the
    690      * specified value. Animations already running on the property will be canceled.
    691      *
    692      * @param value The amount to be animated by, as an offset from the current value.
    693      * @see View#setScaleX(float)
    694      * @return This object, allowing calls to methods in this class to be chained.
    695      */
    696     public ViewPropertyAnimator scaleXBy(float value) {
    697         animatePropertyBy(SCALE_X, value);
    698         return this;
    699     }
    700 
    701     /**
    702      * This method will cause the View's <code>scaleY</code> property to be animated to the
    703      * specified value. Animations already running on the property will be canceled.
    704      *
    705      * @param value The value to be animated to.
    706      * @see View#setScaleY(float)
    707      * @return This object, allowing calls to methods in this class to be chained.
    708      */
    709     public ViewPropertyAnimator scaleY(float value) {
    710         animateProperty(SCALE_Y, value);
    711         return this;
    712     }
    713 
    714     /**
    715      * This method will cause the View's <code>scaleY</code> property to be animated by the
    716      * specified value. Animations already running on the property will be canceled.
    717      *
    718      * @param value The amount to be animated by, as an offset from the current value.
    719      * @see View#setScaleY(float)
    720      * @return This object, allowing calls to methods in this class to be chained.
    721      */
    722     public ViewPropertyAnimator scaleYBy(float value) {
    723         animatePropertyBy(SCALE_Y, value);
    724         return this;
    725     }
    726 
    727     /**
    728      * This method will cause the View's <code>alpha</code> property to be animated to the
    729      * specified value. Animations already running on the property will be canceled.
    730      *
    731      * @param value The value to be animated to.
    732      * @see View#setAlpha(float)
    733      * @return This object, allowing calls to methods in this class to be chained.
    734      */
    735     public ViewPropertyAnimator alpha(float value) {
    736         animateProperty(ALPHA, value);
    737         return this;
    738     }
    739 
    740     /**
    741      * This method will cause the View's <code>alpha</code> property to be animated by the
    742      * specified value. Animations already running on the property will be canceled.
    743      *
    744      * @param value The amount to be animated by, as an offset from the current value.
    745      * @see View#setAlpha(float)
    746      * @return This object, allowing calls to methods in this class to be chained.
    747      */
    748     public ViewPropertyAnimator alphaBy(float value) {
    749         animatePropertyBy(ALPHA, value);
    750         return this;
    751     }
    752 
    753     /**
    754      * The View associated with this ViewPropertyAnimator will have its
    755      * {@link View#setLayerType(int, android.graphics.Paint) layer type} set to
    756      * {@link View#LAYER_TYPE_HARDWARE} for the duration of the next animation.
    757      * As stated in the documentation for {@link View#LAYER_TYPE_HARDWARE},
    758      * the actual type of layer used internally depends on the runtime situation of the
    759      * view. If the activity and this view are hardware-accelerated, then the layer will be
    760      * accelerated as well. If the activity or the view is not accelerated, then the layer will
    761      * effectively be the same as {@link View#LAYER_TYPE_SOFTWARE}.
    762      *
    763      * <p>This state is not persistent, either on the View or on this ViewPropertyAnimator: the
    764      * layer type of the View will be restored when the animation ends to what it was when this
    765      * method was called, and this setting on ViewPropertyAnimator is only valid for the next
    766      * animation. Note that calling this method and then independently setting the layer type of
    767      * the View (by a direct call to {@link View#setLayerType(int, android.graphics.Paint)}) will
    768      * result in some inconsistency, including having the layer type restored to its pre-withLayer()
    769      * value when the animation ends.</p>
    770      *
    771      * @see View#setLayerType(int, android.graphics.Paint)
    772      * @return This object, allowing calls to methods in this class to be chained.
    773      */
    774     public ViewPropertyAnimator withLayer() {
    775          mPendingSetupAction= new Runnable() {
    776             @Override
    777             public void run() {
    778                 mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
    779                 if (mView.isAttachedToWindow()) {
    780                     mView.buildLayer();
    781                 }
    782             }
    783         };
    784         final int currentLayerType = mView.getLayerType();
    785         mPendingCleanupAction = new Runnable() {
    786             @Override
    787             public void run() {
    788                 mView.setLayerType(currentLayerType, null);
    789             }
    790         };
    791         if (mAnimatorSetupMap == null) {
    792             mAnimatorSetupMap = new HashMap<Animator, Runnable>();
    793         }
    794         if (mAnimatorCleanupMap == null) {
    795             mAnimatorCleanupMap = new HashMap<Animator, Runnable>();
    796         }
    797 
    798         return this;
    799     }
    800 
    801     /**
    802      * Specifies an action to take place when the next animation runs. If there is a
    803      * {@link #setStartDelay(long) startDelay} set on this ViewPropertyAnimator, then the
    804      * action will run after that startDelay expires, when the actual animation begins.
    805      * This method, along with {@link #withEndAction(Runnable)}, is intended to help facilitate
    806      * choreographing ViewPropertyAnimator animations with other animations or actions
    807      * in the application.
    808      *
    809      * @param runnable The action to run when the next animation starts.
    810      * @return This object, allowing calls to methods in this class to be chained.
    811      */
    812     public ViewPropertyAnimator withStartAction(Runnable runnable) {
    813         mPendingOnStartAction = runnable;
    814         if (runnable != null && mAnimatorOnStartMap == null) {
    815             mAnimatorOnStartMap = new HashMap<Animator, Runnable>();
    816         }
    817         return this;
    818     }
    819 
    820     /**
    821      * Specifies an action to take place when the next animation ends. The action is only
    822      * run if the animation ends normally; if the ViewPropertyAnimator is canceled during
    823      * that animation, the runnable will not run.
    824      * This method, along with {@link #withStartAction(Runnable)}, is intended to help facilitate
    825      * choreographing ViewPropertyAnimator animations with other animations or actions
    826      * in the application.
    827      *
    828      * <p>For example, the following code animates a view to x=200 and then back to 0:</p>
    829      * <pre>
    830      *     Runnable endAction = new Runnable() {
    831      *         public void run() {
    832      *             view.animate().x(0);
    833      *         }
    834      *     };
    835      *     view.animate().x(200).withEndAction(endAction);
    836      * </pre>
    837      *
    838      * @param runnable The action to run when the next animation ends.
    839      * @return This object, allowing calls to methods in this class to be chained.
    840      */
    841     public ViewPropertyAnimator withEndAction(Runnable runnable) {
    842         mPendingOnEndAction = runnable;
    843         if (runnable != null && mAnimatorOnEndMap == null) {
    844             mAnimatorOnEndMap = new HashMap<Animator, Runnable>();
    845         }
    846         return this;
    847     }
    848 
    849     boolean hasActions() {
    850         return mPendingSetupAction != null
    851                 || mPendingCleanupAction != null
    852                 || mPendingOnStartAction != null
    853                 || mPendingOnEndAction != null;
    854     }
    855 
    856     /**
    857      * Starts the underlying Animator for a set of properties. We use a single animator that
    858      * simply runs from 0 to 1, and then use that fractional value to set each property
    859      * value accordingly.
    860      */
    861     private void startAnimation() {
    862         if (mRTBackend != null && mRTBackend.startAnimation(this)) {
    863             return;
    864         }
    865         mView.setHasTransientState(true);
    866         ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
    867         ArrayList<NameValuesHolder> nameValueList =
    868                 (ArrayList<NameValuesHolder>) mPendingAnimations.clone();
    869         mPendingAnimations.clear();
    870         int propertyMask = 0;
    871         int propertyCount = nameValueList.size();
    872         for (int i = 0; i < propertyCount; ++i) {
    873             NameValuesHolder nameValuesHolder = nameValueList.get(i);
    874             propertyMask |= nameValuesHolder.mNameConstant;
    875         }
    876         mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
    877         if (mPendingSetupAction != null) {
    878             mAnimatorSetupMap.put(animator, mPendingSetupAction);
    879             mPendingSetupAction = null;
    880         }
    881         if (mPendingCleanupAction != null) {
    882             mAnimatorCleanupMap.put(animator, mPendingCleanupAction);
    883             mPendingCleanupAction = null;
    884         }
    885         if (mPendingOnStartAction != null) {
    886             mAnimatorOnStartMap.put(animator, mPendingOnStartAction);
    887             mPendingOnStartAction = null;
    888         }
    889         if (mPendingOnEndAction != null) {
    890             mAnimatorOnEndMap.put(animator, mPendingOnEndAction);
    891             mPendingOnEndAction = null;
    892         }
    893         animator.addUpdateListener(mAnimatorEventListener);
    894         animator.addListener(mAnimatorEventListener);
    895         if (mStartDelaySet) {
    896             animator.setStartDelay(mStartDelay);
    897         }
    898         if (mDurationSet) {
    899             animator.setDuration(mDuration);
    900         }
    901         if (mInterpolatorSet) {
    902             animator.setInterpolator(mInterpolator);
    903         }
    904         animator.start();
    905     }
    906 
    907     /**
    908      * Utility function, called by the various x(), y(), etc. methods. This stores the
    909      * constant name for the property along with the from/delta values that will be used to
    910      * calculate and set the property during the animation. This structure is added to the
    911      * pending animations, awaiting the eventual start() of the underlying animator. A
    912      * Runnable is posted to start the animation, and any pending such Runnable is canceled
    913      * (which enables us to end up starting just one animator for all of the properties
    914      * specified at one time).
    915      *
    916      * @param constantName The specifier for the property being animated
    917      * @param toValue The value to which the property will animate
    918      */
    919     private void animateProperty(int constantName, float toValue) {
    920         float fromValue = getValue(constantName);
    921         float deltaValue = toValue - fromValue;
    922         animatePropertyBy(constantName, fromValue, deltaValue);
    923     }
    924 
    925     /**
    926      * Utility function, called by the various xBy(), yBy(), etc. methods. This method is
    927      * just like animateProperty(), except the value is an offset from the property's
    928      * current value, instead of an absolute "to" value.
    929      *
    930      * @param constantName The specifier for the property being animated
    931      * @param byValue The amount by which the property will change
    932      */
    933     private void animatePropertyBy(int constantName, float byValue) {
    934         float fromValue = getValue(constantName);
    935         animatePropertyBy(constantName, fromValue, byValue);
    936     }
    937 
    938     /**
    939      * Utility function, called by animateProperty() and animatePropertyBy(), which handles the
    940      * details of adding a pending animation and posting the request to start the animation.
    941      *
    942      * @param constantName The specifier for the property being animated
    943      * @param startValue The starting value of the property
    944      * @param byValue The amount by which the property will change
    945      */
    946     private void animatePropertyBy(int constantName, float startValue, float byValue) {
    947         // First, cancel any existing animations on this property
    948         if (mAnimatorMap.size() > 0) {
    949             Animator animatorToCancel = null;
    950             Set<Animator> animatorSet = mAnimatorMap.keySet();
    951             for (Animator runningAnim : animatorSet) {
    952                 PropertyBundle bundle = mAnimatorMap.get(runningAnim);
    953                 if (bundle.cancel(constantName)) {
    954                     // property was canceled - cancel the animation if it's now empty
    955                     // Note that it's safe to break out here because every new animation
    956                     // on a property will cancel a previous animation on that property, so
    957                     // there can only ever be one such animation running.
    958                     if (bundle.mPropertyMask == NONE) {
    959                         // the animation is no longer changing anything - cancel it
    960                         animatorToCancel = runningAnim;
    961                         break;
    962                     }
    963                 }
    964             }
    965             if (animatorToCancel != null) {
    966                 animatorToCancel.cancel();
    967             }
    968         }
    969 
    970         NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
    971         mPendingAnimations.add(nameValuePair);
    972         mView.removeCallbacks(mAnimationStarter);
    973         mView.postOnAnimation(mAnimationStarter);
    974     }
    975 
    976     /**
    977      * This method handles setting the property values directly in the View object's fields.
    978      * propertyConstant tells it which property should be set, value is the value to set
    979      * the property to.
    980      *
    981      * @param propertyConstant The property to be set
    982      * @param value The value to set the property to
    983      */
    984     private void setValue(int propertyConstant, float value) {
    985         final View.TransformationInfo info = mView.mTransformationInfo;
    986         final RenderNode renderNode = mView.mRenderNode;
    987         switch (propertyConstant) {
    988             case TRANSLATION_X:
    989                 renderNode.setTranslationX(value);
    990                 break;
    991             case TRANSLATION_Y:
    992                 renderNode.setTranslationY(value);
    993                 break;
    994             case TRANSLATION_Z:
    995                 renderNode.setTranslationZ(value);
    996                 break;
    997             case ROTATION:
    998                 renderNode.setRotation(value);
    999                 break;
   1000             case ROTATION_X:
   1001                 renderNode.setRotationX(value);
   1002                 break;
   1003             case ROTATION_Y:
   1004                 renderNode.setRotationY(value);
   1005                 break;
   1006             case SCALE_X:
   1007                 renderNode.setScaleX(value);
   1008                 break;
   1009             case SCALE_Y:
   1010                 renderNode.setScaleY(value);
   1011                 break;
   1012             case X:
   1013                 renderNode.setTranslationX(value - mView.mLeft);
   1014                 break;
   1015             case Y:
   1016                 renderNode.setTranslationY(value - mView.mTop);
   1017                 break;
   1018             case Z:
   1019                 renderNode.setTranslationZ(value - renderNode.getElevation());
   1020                 break;
   1021             case ALPHA:
   1022                 info.mAlpha = value;
   1023                 renderNode.setAlpha(value);
   1024                 break;
   1025         }
   1026     }
   1027 
   1028     /**
   1029      * This method gets the value of the named property from the View object.
   1030      *
   1031      * @param propertyConstant The property whose value should be returned
   1032      * @return float The value of the named property
   1033      */
   1034     private float getValue(int propertyConstant) {
   1035         final RenderNode node = mView.mRenderNode;
   1036         switch (propertyConstant) {
   1037             case TRANSLATION_X:
   1038                 return node.getTranslationX();
   1039             case TRANSLATION_Y:
   1040                 return node.getTranslationY();
   1041             case TRANSLATION_Z:
   1042                 return node.getTranslationZ();
   1043             case ROTATION:
   1044                 return node.getRotation();
   1045             case ROTATION_X:
   1046                 return node.getRotationX();
   1047             case ROTATION_Y:
   1048                 return node.getRotationY();
   1049             case SCALE_X:
   1050                 return node.getScaleX();
   1051             case SCALE_Y:
   1052                 return node.getScaleY();
   1053             case X:
   1054                 return mView.mLeft + node.getTranslationX();
   1055             case Y:
   1056                 return mView.mTop + node.getTranslationY();
   1057             case Z:
   1058                 return node.getElevation() + node.getTranslationZ();
   1059             case ALPHA:
   1060                 return mView.mTransformationInfo.mAlpha;
   1061         }
   1062         return 0;
   1063     }
   1064 
   1065     /**
   1066      * Utility class that handles the various Animator events. The only ones we care
   1067      * about are the end event (which we use to clean up the animator map when an animator
   1068      * finishes) and the update event (which we use to calculate the current value of each
   1069      * property and then set it on the view object).
   1070      */
   1071     private class AnimatorEventListener
   1072             implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
   1073         @Override
   1074         public void onAnimationStart(Animator animation) {
   1075             if (mAnimatorSetupMap != null) {
   1076                 Runnable r = mAnimatorSetupMap.get(animation);
   1077                 if (r != null) {
   1078                     r.run();
   1079                 }
   1080                 mAnimatorSetupMap.remove(animation);
   1081             }
   1082             if (mAnimatorOnStartMap != null) {
   1083                 Runnable r = mAnimatorOnStartMap.get(animation);
   1084                 if (r != null) {
   1085                     r.run();
   1086                 }
   1087                 mAnimatorOnStartMap.remove(animation);
   1088             }
   1089             if (mListener != null) {
   1090                 mListener.onAnimationStart(animation);
   1091             }
   1092         }
   1093 
   1094         @Override
   1095         public void onAnimationCancel(Animator animation) {
   1096             if (mListener != null) {
   1097                 mListener.onAnimationCancel(animation);
   1098             }
   1099             if (mAnimatorOnEndMap != null) {
   1100                 mAnimatorOnEndMap.remove(animation);
   1101             }
   1102         }
   1103 
   1104         @Override
   1105         public void onAnimationRepeat(Animator animation) {
   1106             if (mListener != null) {
   1107                 mListener.onAnimationRepeat(animation);
   1108             }
   1109         }
   1110 
   1111         @Override
   1112         public void onAnimationEnd(Animator animation) {
   1113             mView.setHasTransientState(false);
   1114             if (mAnimatorCleanupMap != null) {
   1115                 Runnable r = mAnimatorCleanupMap.get(animation);
   1116                 if (r != null) {
   1117                     r.run();
   1118                 }
   1119                 mAnimatorCleanupMap.remove(animation);
   1120             }
   1121             if (mListener != null) {
   1122                 mListener.onAnimationEnd(animation);
   1123             }
   1124             if (mAnimatorOnEndMap != null) {
   1125                 Runnable r = mAnimatorOnEndMap.get(animation);
   1126                 if (r != null) {
   1127                     r.run();
   1128                 }
   1129                 mAnimatorOnEndMap.remove(animation);
   1130             }
   1131             mAnimatorMap.remove(animation);
   1132         }
   1133 
   1134         /**
   1135          * Calculate the current value for each property and set it on the view. Invalidate
   1136          * the view object appropriately, depending on which properties are being animated.
   1137          *
   1138          * @param animation The animator associated with the properties that need to be
   1139          * set. This animator holds the animation fraction which we will use to calculate
   1140          * the current value of each property.
   1141          */
   1142         @Override
   1143         public void onAnimationUpdate(ValueAnimator animation) {
   1144             PropertyBundle propertyBundle = mAnimatorMap.get(animation);
   1145             if (propertyBundle == null) {
   1146                 // Shouldn't happen, but just to play it safe
   1147                 return;
   1148             }
   1149 
   1150             boolean hardwareAccelerated = mView.isHardwareAccelerated();
   1151 
   1152             // alpha requires slightly different treatment than the other (transform) properties.
   1153             // The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
   1154             // logic is dependent on how the view handles an internal call to onSetAlpha().
   1155             // We track what kinds of properties are set, and how alpha is handled when it is
   1156             // set, and perform the invalidation steps appropriately.
   1157             boolean alphaHandled = false;
   1158             if (!hardwareAccelerated) {
   1159                 mView.invalidateParentCaches();
   1160             }
   1161             float fraction = animation.getAnimatedFraction();
   1162             int propertyMask = propertyBundle.mPropertyMask;
   1163             if ((propertyMask & TRANSFORM_MASK) != 0) {
   1164                 mView.invalidateViewProperty(hardwareAccelerated, false);
   1165             }
   1166             ArrayList<NameValuesHolder> valueList = propertyBundle.mNameValuesHolder;
   1167             if (valueList != null) {
   1168                 int count = valueList.size();
   1169                 for (int i = 0; i < count; ++i) {
   1170                     NameValuesHolder values = valueList.get(i);
   1171                     float value = values.mFromValue + fraction * values.mDeltaValue;
   1172                     if (values.mNameConstant == ALPHA) {
   1173                         alphaHandled = mView.setAlphaNoInvalidation(value);
   1174                     } else {
   1175                         setValue(values.mNameConstant, value);
   1176                     }
   1177                 }
   1178             }
   1179             if ((propertyMask & TRANSFORM_MASK) != 0) {
   1180                 if (!hardwareAccelerated) {
   1181                     mView.mPrivateFlags |= View.PFLAG_DRAWN; // force another invalidation
   1182                 }
   1183             }
   1184             // invalidate(false) in all cases except if alphaHandled gets set to true
   1185             // via the call to setAlphaNoInvalidation(), above
   1186             if (alphaHandled) {
   1187                 mView.invalidate(true);
   1188             } else {
   1189                 mView.invalidateViewProperty(false, false);
   1190             }
   1191             if (mUpdateListener != null) {
   1192                 mUpdateListener.onAnimationUpdate(animation);
   1193             }
   1194         }
   1195     }
   1196 }
   1197