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