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