Home | History | Annotate | Download | only in animation
      1 /*
      2  * Copyright (C) 2010 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.animation;
     18 
     19 import android.annotation.NonNull;
     20 import android.annotation.Nullable;
     21 import android.graphics.Path;
     22 import android.graphics.PointF;
     23 import android.util.Log;
     24 import android.util.Property;
     25 
     26 import java.lang.ref.WeakReference;
     27 import java.util.ArrayList;
     28 
     29 /**
     30  * This subclass of {@link ValueAnimator} provides support for animating properties on target objects.
     31  * The constructors of this class take parameters to define the target object that will be animated
     32  * as well as the name of the property that will be animated. Appropriate set/get functions
     33  * are then determined internally and the animation will call these functions as necessary to
     34  * animate the property.
     35  *
     36  * <div class="special reference">
     37  * <h3>Developer Guides</h3>
     38  * <p>For more information about animating with {@code ObjectAnimator}, read the
     39  * <a href="{@docRoot}guide/topics/graphics/prop-animation.html#object-animator">Property
     40  * Animation</a> developer guide.</p>
     41  * </div>
     42  *
     43  * @see #setPropertyName(String)
     44  *
     45  */
     46 public final class ObjectAnimator extends ValueAnimator {
     47     private static final String LOG_TAG = "ObjectAnimator";
     48 
     49     private static final boolean DBG = false;
     50 
     51     /**
     52      * A weak reference to the target object on which the property exists, set
     53      * in the constructor. We'll cancel the animation if this goes away.
     54      */
     55     private WeakReference<Object> mTarget;
     56 
     57     private String mPropertyName;
     58 
     59     private Property mProperty;
     60 
     61     private boolean mAutoCancel = false;
     62 
     63     /**
     64      * Sets the name of the property that will be animated. This name is used to derive
     65      * a setter function that will be called to set animated values.
     66      * For example, a property name of <code>foo</code> will result
     67      * in a call to the function <code>setFoo()</code> on the target object. If either
     68      * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
     69      * also be derived and called.
     70      *
     71      * <p>For best performance of the mechanism that calls the setter function determined by the
     72      * name of the property being animated, use <code>float</code> or <code>int</code> typed values,
     73      * and make the setter function for those properties have a <code>void</code> return value. This
     74      * will cause the code to take an optimized path for these constrained circumstances. Other
     75      * property types and return types will work, but will have more overhead in processing
     76      * the requests due to normal reflection mechanisms.</p>
     77      *
     78      * <p>Note that the setter function derived from this property name
     79      * must take the same parameter type as the
     80      * <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to
     81      * the setter function will fail.</p>
     82      *
     83      * <p>If this ObjectAnimator has been set up to animate several properties together,
     84      * using more than one PropertyValuesHolder objects, then setting the propertyName simply
     85      * sets the propertyName in the first of those PropertyValuesHolder objects.</p>
     86      *
     87      * @param propertyName The name of the property being animated. Should not be null.
     88      */
     89     public void setPropertyName(@NonNull String propertyName) {
     90         // mValues could be null if this is being constructed piecemeal. Just record the
     91         // propertyName to be used later when setValues() is called if so.
     92         if (mValues != null) {
     93             PropertyValuesHolder valuesHolder = mValues[0];
     94             String oldName = valuesHolder.getPropertyName();
     95             valuesHolder.setPropertyName(propertyName);
     96             mValuesMap.remove(oldName);
     97             mValuesMap.put(propertyName, valuesHolder);
     98         }
     99         mPropertyName = propertyName;
    100         // New property/values/target should cause re-initialization prior to starting
    101         mInitialized = false;
    102     }
    103 
    104     /**
    105      * Sets the property that will be animated. Property objects will take precedence over
    106      * properties specified by the {@link #setPropertyName(String)} method. Animations should
    107      * be set up to use one or the other, not both.
    108      *
    109      * @param property The property being animated. Should not be null.
    110      */
    111     public void setProperty(@NonNull Property property) {
    112         // mValues could be null if this is being constructed piecemeal. Just record the
    113         // propertyName to be used later when setValues() is called if so.
    114         if (mValues != null) {
    115             PropertyValuesHolder valuesHolder = mValues[0];
    116             String oldName = valuesHolder.getPropertyName();
    117             valuesHolder.setProperty(property);
    118             mValuesMap.remove(oldName);
    119             mValuesMap.put(mPropertyName, valuesHolder);
    120         }
    121         if (mProperty != null) {
    122             mPropertyName = property.getName();
    123         }
    124         mProperty = property;
    125         // New property/values/target should cause re-initialization prior to starting
    126         mInitialized = false;
    127     }
    128 
    129     /**
    130      * Gets the name of the property that will be animated. This name will be used to derive
    131      * a setter function that will be called to set animated values.
    132      * For example, a property name of <code>foo</code> will result
    133      * in a call to the function <code>setFoo()</code> on the target object. If either
    134      * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
    135      * also be derived and called.
    136      *
    137      * <p>If this animator was created with a {@link Property} object instead of the
    138      * string name of a property, then this method will return the {@link
    139      * Property#getName() name} of that Property object instead. If this animator was
    140      * created with one or more {@link PropertyValuesHolder} objects, then this method
    141      * will return the {@link PropertyValuesHolder#getPropertyName() name} of that
    142      * object (if there was just one) or a comma-separated list of all of the
    143      * names (if there are more than one).</p>
    144      */
    145     @Nullable
    146     public String getPropertyName() {
    147         String propertyName = null;
    148         if (mPropertyName != null) {
    149             propertyName = mPropertyName;
    150         } else if (mProperty != null) {
    151             propertyName = mProperty.getName();
    152         } else if (mValues != null && mValues.length > 0) {
    153             for (int i = 0; i < mValues.length; ++i) {
    154                 if (i == 0) {
    155                     propertyName = "";
    156                 } else {
    157                     propertyName += ",";
    158                 }
    159                 propertyName += mValues[i].getPropertyName();
    160             }
    161         }
    162         return propertyName;
    163     }
    164 
    165     @Override
    166     String getNameForTrace() {
    167         return "animator:" + getPropertyName();
    168     }
    169 
    170     /**
    171      * Creates a new ObjectAnimator object. This default constructor is primarily for
    172      * use internally; the other constructors which take parameters are more generally
    173      * useful.
    174      */
    175     public ObjectAnimator() {
    176     }
    177 
    178     /**
    179      * Private utility constructor that initializes the target object and name of the
    180      * property being animated.
    181      *
    182      * @param target The object whose property is to be animated. This object should
    183      * have a public method on it called <code>setName()</code>, where <code>name</code> is
    184      * the value of the <code>propertyName</code> parameter.
    185      * @param propertyName The name of the property being animated.
    186      */
    187     private ObjectAnimator(Object target, String propertyName) {
    188         setTarget(target);
    189         setPropertyName(propertyName);
    190     }
    191 
    192     /**
    193      * Private utility constructor that initializes the target object and property being animated.
    194      *
    195      * @param target The object whose property is to be animated.
    196      * @param property The property being animated.
    197      */
    198     private <T> ObjectAnimator(T target, Property<T, ?> property) {
    199         setTarget(target);
    200         setProperty(property);
    201     }
    202 
    203     /**
    204      * Constructs and returns an ObjectAnimator that animates between int values. A single
    205      * value implies that that value is the one being animated to. Two values imply starting
    206      * and ending values. More than two values imply a starting value, values to animate through
    207      * along the way, and an ending value (these values will be distributed evenly across
    208      * the duration of the animation).
    209      *
    210      * @param target The object whose property is to be animated. This object should
    211      * have a public method on it called <code>setName()</code>, where <code>name</code> is
    212      * the value of the <code>propertyName</code> parameter.
    213      * @param propertyName The name of the property being animated.
    214      * @param values A set of values that the animation will animate between over time.
    215      * @return An ObjectAnimator object that is set up to animate between the given values.
    216      */
    217     public static ObjectAnimator ofInt(Object target, String propertyName, int... values) {
    218         ObjectAnimator anim = new ObjectAnimator(target, propertyName);
    219         anim.setIntValues(values);
    220         return anim;
    221     }
    222 
    223     /**
    224      * Constructs and returns an ObjectAnimator that animates coordinates along a <code>Path</code>
    225      * using two properties. A <code>Path</code></> animation moves in two dimensions, animating
    226      * coordinates <code>(x, y)</code> together to follow the line. In this variation, the
    227      * coordinates are integers that are set to separate properties designated by
    228      * <code>xPropertyName</code> and <code>yPropertyName</code>.
    229      *
    230      * @param target The object whose properties are to be animated. This object should
    231      *               have public methods on it called <code>setNameX()</code> and
    232      *               <code>setNameY</code>, where <code>nameX</code> and <code>nameY</code>
    233      *               are the value of <code>xPropertyName</code> and <code>yPropertyName</code>
    234      *               parameters, respectively.
    235      * @param xPropertyName The name of the property for the x coordinate being animated.
    236      * @param yPropertyName The name of the property for the y coordinate being animated.
    237      * @param path The <code>Path</code> to animate values along.
    238      * @return An ObjectAnimator object that is set up to animate along <code>path</code>.
    239      */
    240     public static ObjectAnimator ofInt(Object target, String xPropertyName, String yPropertyName,
    241             Path path) {
    242         PathKeyframes keyframes = KeyframeSet.ofPath(path);
    243         PropertyValuesHolder x = PropertyValuesHolder.ofKeyframes(xPropertyName,
    244                 keyframes.createXIntKeyframes());
    245         PropertyValuesHolder y = PropertyValuesHolder.ofKeyframes(yPropertyName,
    246                 keyframes.createYIntKeyframes());
    247         return ofPropertyValuesHolder(target, x, y);
    248     }
    249 
    250     /**
    251      * Constructs and returns an ObjectAnimator that animates between int values. A single
    252      * value implies that that value is the one being animated to. Two values imply starting
    253      * and ending values. More than two values imply a starting value, values to animate through
    254      * along the way, and an ending value (these values will be distributed evenly across
    255      * the duration of the animation).
    256      *
    257      * @param target The object whose property is to be animated.
    258      * @param property The property being animated.
    259      * @param values A set of values that the animation will animate between over time.
    260      * @return An ObjectAnimator object that is set up to animate between the given values.
    261      */
    262     public static <T> ObjectAnimator ofInt(T target, Property<T, Integer> property, int... values) {
    263         ObjectAnimator anim = new ObjectAnimator(target, property);
    264         anim.setIntValues(values);
    265         return anim;
    266     }
    267 
    268     /**
    269      * Constructs and returns an ObjectAnimator that animates coordinates along a <code>Path</code>
    270      * using two properties.  A <code>Path</code></> animation moves in two dimensions, animating
    271      * coordinates <code>(x, y)</code> together to follow the line. In this variation, the
    272      * coordinates are integers that are set to separate properties, <code>xProperty</code> and
    273      * <code>yProperty</code>.
    274      *
    275      * @param target The object whose properties are to be animated.
    276      * @param xProperty The property for the x coordinate being animated.
    277      * @param yProperty The property for the y coordinate being animated.
    278      * @param path The <code>Path</code> to animate values along.
    279      * @return An ObjectAnimator object that is set up to animate along <code>path</code>.
    280      */
    281     public static <T> ObjectAnimator ofInt(T target, Property<T, Integer> xProperty,
    282             Property<T, Integer> yProperty, Path path) {
    283         PathKeyframes keyframes = KeyframeSet.ofPath(path);
    284         PropertyValuesHolder x = PropertyValuesHolder.ofKeyframes(xProperty,
    285                 keyframes.createXIntKeyframes());
    286         PropertyValuesHolder y = PropertyValuesHolder.ofKeyframes(yProperty,
    287                 keyframes.createYIntKeyframes());
    288         return ofPropertyValuesHolder(target, x, y);
    289     }
    290 
    291     /**
    292      * Constructs and returns an ObjectAnimator that animates over int values for a multiple
    293      * parameters setter. Only public methods that take only int parameters are supported.
    294      * Each <code>int[]</code> contains a complete set of parameters to the setter method.
    295      * At least two <code>int[]</code> values must be provided, a start and end. More than two
    296      * values imply a starting value, values to animate through along the way, and an ending
    297      * value (these values will be distributed evenly across the duration of the animation).
    298      *
    299      * @param target The object whose property is to be animated. This object may
    300      * have a public method on it called <code>setName()</code>, where <code>name</code> is
    301      * the value of the <code>propertyName</code> parameter. <code>propertyName</code> may also
    302      * be the case-sensitive complete name of the public setter method.
    303      * @param propertyName The name of the property being animated or the name of the setter method.
    304      * @param values A set of values that the animation will animate between over time.
    305      * @return An ObjectAnimator object that is set up to animate between the given values.
    306      */
    307     public static ObjectAnimator ofMultiInt(Object target, String propertyName, int[][] values) {
    308         PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiInt(propertyName, values);
    309         return ofPropertyValuesHolder(target, pvh);
    310     }
    311 
    312     /**
    313      * Constructs and returns an ObjectAnimator that animates the target using a multi-int setter
    314      * along the given <code>Path</code>. A <code>Path</code></> animation moves in two dimensions,
    315      * animating coordinates <code>(x, y)</code> together to follow the line. In this variation, the
    316      * coordinates are integer x and y coordinates used in the first and second parameter of the
    317      * setter, respectively.
    318      *
    319      * @param target The object whose property is to be animated. This object may
    320      * have a public method on it called <code>setName()</code>, where <code>name</code> is
    321      * the value of the <code>propertyName</code> parameter. <code>propertyName</code> may also
    322      * be the case-sensitive complete name of the public setter method.
    323      * @param propertyName The name of the property being animated or the name of the setter method.
    324      * @param path The <code>Path</code> to animate values along.
    325      * @return An ObjectAnimator object that is set up to animate along <code>path</code>.
    326      */
    327     public static ObjectAnimator ofMultiInt(Object target, String propertyName, Path path) {
    328         PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiInt(propertyName, path);
    329         return ofPropertyValuesHolder(target, pvh);
    330     }
    331 
    332     /**
    333      * Constructs and returns an ObjectAnimator that animates over values for a multiple int
    334      * parameters setter. Only public methods that take only int parameters are supported.
    335      * <p>At least two values must be provided, a start and end. More than two
    336      * values imply a starting value, values to animate through along the way, and an ending
    337      * value (these values will be distributed evenly across the duration of the animation).</p>
    338      *
    339      * @param target The object whose property is to be animated. This object may
    340      * have a public method on it called <code>setName()</code>, where <code>name</code> is
    341      * the value of the <code>propertyName</code> parameter. <code>propertyName</code> may also
    342      * be the case-sensitive complete name of the public setter method.
    343      * @param propertyName The name of the property being animated or the name of the setter method.
    344      * @param converter Converts T objects into int parameters for the multi-value setter.
    345      * @param evaluator A TypeEvaluator that will be called on each animation frame to
    346      * provide the necessary interpolation between the Object values to derive the animated
    347      * value.
    348      * @param values A set of values that the animation will animate between over time.
    349      * @return An ObjectAnimator object that is set up to animate between the given values.
    350      */
    351     public static <T> ObjectAnimator ofMultiInt(Object target, String propertyName,
    352             TypeConverter<T, int[]> converter, TypeEvaluator<T> evaluator, T... values) {
    353         PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiInt(propertyName, converter,
    354                 evaluator, values);
    355         return ObjectAnimator.ofPropertyValuesHolder(target, pvh);
    356     }
    357 
    358     /**
    359      * Constructs and returns an ObjectAnimator that animates between color values. A single
    360      * value implies that that value is the one being animated to. Two values imply starting
    361      * and ending values. More than two values imply a starting value, values to animate through
    362      * along the way, and an ending value (these values will be distributed evenly across
    363      * the duration of the animation).
    364      *
    365      * @param target The object whose property is to be animated. This object should
    366      * have a public method on it called <code>setName()</code>, where <code>name</code> is
    367      * the value of the <code>propertyName</code> parameter.
    368      * @param propertyName The name of the property being animated.
    369      * @param values A set of values that the animation will animate between over time.
    370      * @return An ObjectAnimator object that is set up to animate between the given values.
    371      */
    372     public static ObjectAnimator ofArgb(Object target, String propertyName, int... values) {
    373         ObjectAnimator animator = ofInt(target, propertyName, values);
    374         animator.setEvaluator(ArgbEvaluator.getInstance());
    375         return animator;
    376     }
    377 
    378     /**
    379      * Constructs and returns an ObjectAnimator that animates between color values. A single
    380      * value implies that that value is the one being animated to. Two values imply starting
    381      * and ending values. More than two values imply a starting value, values to animate through
    382      * along the way, and an ending value (these values will be distributed evenly across
    383      * the duration of the animation).
    384      *
    385      * @param target The object whose property is to be animated.
    386      * @param property The property being animated.
    387      * @param values A set of values that the animation will animate between over time.
    388      * @return An ObjectAnimator object that is set up to animate between the given values.
    389      */
    390     public static <T> ObjectAnimator ofArgb(T target, Property<T, Integer> property,
    391             int... values) {
    392         ObjectAnimator animator = ofInt(target, property, values);
    393         animator.setEvaluator(ArgbEvaluator.getInstance());
    394         return animator;
    395     }
    396 
    397     /**
    398      * Constructs and returns an ObjectAnimator that animates between float values. A single
    399      * value implies that that value is the one being animated to. Two values imply starting
    400      * and ending values. More than two values imply a starting value, values to animate through
    401      * along the way, and an ending value (these values will be distributed evenly across
    402      * the duration of the animation).
    403      *
    404      * @param target The object whose property is to be animated. This object should
    405      * have a public method on it called <code>setName()</code>, where <code>name</code> is
    406      * the value of the <code>propertyName</code> parameter.
    407      * @param propertyName The name of the property being animated.
    408      * @param values A set of values that the animation will animate between over time.
    409      * @return An ObjectAnimator object that is set up to animate between the given values.
    410      */
    411     public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
    412         ObjectAnimator anim = new ObjectAnimator(target, propertyName);
    413         anim.setFloatValues(values);
    414         return anim;
    415     }
    416 
    417     /**
    418      * Constructs and returns an ObjectAnimator that animates coordinates along a <code>Path</code>
    419      * using two properties. A <code>Path</code></> animation moves in two dimensions, animating
    420      * coordinates <code>(x, y)</code> together to follow the line. In this variation, the
    421      * coordinates are floats that are set to separate properties designated by
    422      * <code>xPropertyName</code> and <code>yPropertyName</code>.
    423      *
    424      * @param target The object whose properties are to be animated. This object should
    425      *               have public methods on it called <code>setNameX()</code> and
    426      *               <code>setNameY</code>, where <code>nameX</code> and <code>nameY</code>
    427      *               are the value of the <code>xPropertyName</code> and <code>yPropertyName</code>
    428      *               parameters, respectively.
    429      * @param xPropertyName The name of the property for the x coordinate being animated.
    430      * @param yPropertyName The name of the property for the y coordinate being animated.
    431      * @param path The <code>Path</code> to animate values along.
    432      * @return An ObjectAnimator object that is set up to animate along <code>path</code>.
    433      */
    434     public static ObjectAnimator ofFloat(Object target, String xPropertyName, String yPropertyName,
    435             Path path) {
    436         PathKeyframes keyframes = KeyframeSet.ofPath(path);
    437         PropertyValuesHolder x = PropertyValuesHolder.ofKeyframes(xPropertyName,
    438                 keyframes.createXFloatKeyframes());
    439         PropertyValuesHolder y = PropertyValuesHolder.ofKeyframes(yPropertyName,
    440                 keyframes.createYFloatKeyframes());
    441         return ofPropertyValuesHolder(target, x, y);
    442     }
    443 
    444     /**
    445      * Constructs and returns an ObjectAnimator that animates between float values. A single
    446      * value implies that that value is the one being animated to. Two values imply starting
    447      * and ending values. More than two values imply a starting value, values to animate through
    448      * along the way, and an ending value (these values will be distributed evenly across
    449      * the duration of the animation).
    450      *
    451      * @param target The object whose property is to be animated.
    452      * @param property The property being animated.
    453      * @param values A set of values that the animation will animate between over time.
    454      * @return An ObjectAnimator object that is set up to animate between the given values.
    455      */
    456     public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> property,
    457             float... values) {
    458         ObjectAnimator anim = new ObjectAnimator(target, property);
    459         anim.setFloatValues(values);
    460         return anim;
    461     }
    462 
    463     /**
    464      * Constructs and returns an ObjectAnimator that animates coordinates along a <code>Path</code>
    465      * using two properties. A <code>Path</code></> animation moves in two dimensions, animating
    466      * coordinates <code>(x, y)</code> together to follow the line. In this variation, the
    467      * coordinates are floats that are set to separate properties, <code>xProperty</code> and
    468      * <code>yProperty</code>.
    469      *
    470      * @param target The object whose properties are to be animated.
    471      * @param xProperty The property for the x coordinate being animated.
    472      * @param yProperty The property for the y coordinate being animated.
    473      * @param path The <code>Path</code> to animate values along.
    474      * @return An ObjectAnimator object that is set up to animate along <code>path</code>.
    475      */
    476     public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> xProperty,
    477             Property<T, Float> yProperty, Path path) {
    478         PathKeyframes keyframes = KeyframeSet.ofPath(path);
    479         PropertyValuesHolder x = PropertyValuesHolder.ofKeyframes(xProperty,
    480                 keyframes.createXFloatKeyframes());
    481         PropertyValuesHolder y = PropertyValuesHolder.ofKeyframes(yProperty,
    482                 keyframes.createYFloatKeyframes());
    483         return ofPropertyValuesHolder(target, x, y);
    484     }
    485 
    486     /**
    487      * Constructs and returns an ObjectAnimator that animates over float values for a multiple
    488      * parameters setter. Only public methods that take only float parameters are supported.
    489      * Each <code>float[]</code> contains a complete set of parameters to the setter method.
    490      * At least two <code>float[]</code> values must be provided, a start and end. More than two
    491      * values imply a starting value, values to animate through along the way, and an ending
    492      * value (these values will be distributed evenly across the duration of the animation).
    493      *
    494      * @param target The object whose property is to be animated. This object may
    495      * have a public method on it called <code>setName()</code>, where <code>name</code> is
    496      * the value of the <code>propertyName</code> parameter. <code>propertyName</code> may also
    497      * be the case-sensitive complete name of the public setter method.
    498      * @param propertyName The name of the property being animated or the name of the setter method.
    499      * @param values A set of values that the animation will animate between over time.
    500      * @return An ObjectAnimator object that is set up to animate between the given values.
    501      */
    502     public static ObjectAnimator ofMultiFloat(Object target, String propertyName,
    503             float[][] values) {
    504         PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiFloat(propertyName, values);
    505         return ofPropertyValuesHolder(target, pvh);
    506     }
    507 
    508     /**
    509      * Constructs and returns an ObjectAnimator that animates the target using a multi-float setter
    510      * along the given <code>Path</code>. A <code>Path</code></> animation moves in two dimensions,
    511      * animating coordinates <code>(x, y)</code> together to follow the line. In this variation, the
    512      * coordinates are float x and y coordinates used in the first and second parameter of the
    513      * setter, respectively.
    514      *
    515      * @param target The object whose property is to be animated. This object may
    516      * have a public method on it called <code>setName()</code>, where <code>name</code> is
    517      * the value of the <code>propertyName</code> parameter. <code>propertyName</code> may also
    518      * be the case-sensitive complete name of the public setter method.
    519      * @param propertyName The name of the property being animated or the name of the setter method.
    520      * @param path The <code>Path</code> to animate values along.
    521      * @return An ObjectAnimator object that is set up to animate along <code>path</code>.
    522      */
    523     public static ObjectAnimator ofMultiFloat(Object target, String propertyName, Path path) {
    524         PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiFloat(propertyName, path);
    525         return ofPropertyValuesHolder(target, pvh);
    526     }
    527 
    528     /**
    529      * Constructs and returns an ObjectAnimator that animates over values for a multiple float
    530      * parameters setter. Only public methods that take only float parameters are supported.
    531      * <p>At least two values must be provided, a start and end. More than two
    532      * values imply a starting value, values to animate through along the way, and an ending
    533      * value (these values will be distributed evenly across the duration of the animation).</p>
    534      *
    535      * @param target The object whose property is to be animated. This object may
    536      * have a public method on it called <code>setName()</code>, where <code>name</code> is
    537      * the value of the <code>propertyName</code> parameter. <code>propertyName</code> may also
    538      * be the case-sensitive complete name of the public setter method.
    539      * @param propertyName The name of the property being animated or the name of the setter method.
    540      * @param converter Converts T objects into float parameters for the multi-value setter.
    541      * @param evaluator A TypeEvaluator that will be called on each animation frame to
    542      * provide the necessary interpolation between the Object values to derive the animated
    543      * value.
    544      * @param values A set of values that the animation will animate between over time.
    545      * @return An ObjectAnimator object that is set up to animate between the given values.
    546      */
    547     public static <T> ObjectAnimator ofMultiFloat(Object target, String propertyName,
    548             TypeConverter<T, float[]> converter, TypeEvaluator<T> evaluator, T... values) {
    549         PropertyValuesHolder pvh = PropertyValuesHolder.ofMultiFloat(propertyName, converter,
    550                 evaluator, values);
    551         return ObjectAnimator.ofPropertyValuesHolder(target, pvh);
    552     }
    553 
    554     /**
    555      * Constructs and returns an ObjectAnimator that animates between Object values. A single
    556      * value implies that that value is the one being animated to. Two values imply starting
    557      * and ending values. More than two values imply a starting value, values to animate through
    558      * along the way, and an ending value (these values will be distributed evenly across
    559      * the duration of the animation).
    560      *
    561      * @param target The object whose property is to be animated. This object should
    562      * have a public method on it called <code>setName()</code>, where <code>name</code> is
    563      * the value of the <code>propertyName</code> parameter.
    564      * @param propertyName The name of the property being animated.
    565      * @param evaluator A TypeEvaluator that will be called on each animation frame to
    566      * provide the necessary interpolation between the Object values to derive the animated
    567      * value.
    568      * @param values A set of values that the animation will animate between over time.
    569      * @return An ObjectAnimator object that is set up to animate between the given values.
    570      */
    571     public static ObjectAnimator ofObject(Object target, String propertyName,
    572             TypeEvaluator evaluator, Object... values) {
    573         ObjectAnimator anim = new ObjectAnimator(target, propertyName);
    574         anim.setObjectValues(values);
    575         anim.setEvaluator(evaluator);
    576         return anim;
    577     }
    578 
    579     /**
    580      * Constructs and returns an ObjectAnimator that animates a property along a <code>Path</code>.
    581      * A <code>Path</code></> animation moves in two dimensions, animating coordinates
    582      * <code>(x, y)</code> together to follow the line. This variant animates the coordinates
    583      * in a <code>PointF</code> to follow the <code>Path</code>. If the <code>Property</code>
    584      * associated with <code>propertyName</code> uses a type other than <code>PointF</code>,
    585      * <code>converter</code> can be used to change from <code>PointF</code> to the type
    586      * associated with the <code>Property</code>.
    587      *
    588      * @param target The object whose property is to be animated. This object should
    589      * have a public method on it called <code>setName()</code>, where <code>name</code> is
    590      * the value of the <code>propertyName</code> parameter.
    591      * @param propertyName The name of the property being animated.
    592      * @param converter Converts a PointF to the type associated with the setter. May be
    593      *                  null if conversion is unnecessary.
    594      * @param path The <code>Path</code> to animate values along.
    595      * @return An ObjectAnimator object that is set up to animate along <code>path</code>.
    596      */
    597     @NonNull
    598     public static ObjectAnimator ofObject(Object target, String propertyName,
    599             @Nullable TypeConverter<PointF, ?> converter, Path path) {
    600         PropertyValuesHolder pvh = PropertyValuesHolder.ofObject(propertyName, converter, path);
    601         return ofPropertyValuesHolder(target, pvh);
    602     }
    603 
    604     /**
    605      * Constructs and returns an ObjectAnimator that animates between Object values. A single
    606      * value implies that that value is the one being animated to. Two values imply starting
    607      * and ending values. More than two values imply a starting value, values to animate through
    608      * along the way, and an ending value (these values will be distributed evenly across
    609      * the duration of the animation).
    610      *
    611      * @param target The object whose property is to be animated.
    612      * @param property The property being animated.
    613      * @param evaluator A TypeEvaluator that will be called on each animation frame to
    614      * provide the necessary interpolation between the Object values to derive the animated
    615      * value.
    616      * @param values A set of values that the animation will animate between over time.
    617      * @return An ObjectAnimator object that is set up to animate between the given values.
    618      */
    619     @NonNull
    620     public static <T, V> ObjectAnimator ofObject(T target, Property<T, V> property,
    621             TypeEvaluator<V> evaluator, V... values) {
    622         ObjectAnimator anim = new ObjectAnimator(target, property);
    623         anim.setObjectValues(values);
    624         anim.setEvaluator(evaluator);
    625         return anim;
    626     }
    627 
    628     /**
    629      * Constructs and returns an ObjectAnimator that animates between Object values. A single
    630      * value implies that that value is the one being animated to. Two values imply starting
    631      * and ending values. More than two values imply a starting value, values to animate through
    632      * along the way, and an ending value (these values will be distributed evenly across
    633      * the duration of the animation). This variant supplies a <code>TypeConverter</code> to
    634      * convert from the animated values to the type of the property. If only one value is
    635      * supplied, the <code>TypeConverter</code> must be a
    636      * {@link android.animation.BidirectionalTypeConverter} to retrieve the current value.
    637      *
    638      * @param target The object whose property is to be animated.
    639      * @param property The property being animated.
    640      * @param converter Converts the animated object to the Property type.
    641      * @param evaluator A TypeEvaluator that will be called on each animation frame to
    642      * provide the necessary interpolation between the Object values to derive the animated
    643      * value.
    644      * @param values A set of values that the animation will animate between over time.
    645      * @return An ObjectAnimator object that is set up to animate between the given values.
    646      */
    647     @NonNull
    648     public static <T, V, P> ObjectAnimator ofObject(T target, Property<T, P> property,
    649             TypeConverter<V, P> converter, TypeEvaluator<V> evaluator, V... values) {
    650         PropertyValuesHolder pvh = PropertyValuesHolder.ofObject(property, converter, evaluator,
    651                 values);
    652         return ofPropertyValuesHolder(target, pvh);
    653     }
    654 
    655     /**
    656      * Constructs and returns an ObjectAnimator that animates a property along a <code>Path</code>.
    657      * A <code>Path</code></> animation moves in two dimensions, animating coordinates
    658      * <code>(x, y)</code> together to follow the line. This variant animates the coordinates
    659      * in a <code>PointF</code> to follow the <code>Path</code>. If <code>property</code>
    660      * uses a type other than <code>PointF</code>, <code>converter</code> can be used to change
    661      * from <code>PointF</code> to the type associated with the <code>Property</code>.
    662      *
    663      * <p>The PointF passed to <code>converter</code> or <code>property</code>, if
    664      * <code>converter</code> is <code>null</code>, is reused on each animation frame and should
    665      * not be stored by the setter or TypeConverter.</p>
    666      *
    667      * @param target The object whose property is to be animated.
    668      * @param property The property being animated. Should not be null.
    669      * @param converter Converts a PointF to the type associated with the setter. May be
    670      *                  null if conversion is unnecessary.
    671      * @param path The <code>Path</code> to animate values along.
    672      * @return An ObjectAnimator object that is set up to animate along <code>path</code>.
    673      */
    674     @NonNull
    675     public static <T, V> ObjectAnimator ofObject(T target, @NonNull Property<T, V> property,
    676             @Nullable TypeConverter<PointF, V> converter, Path path) {
    677         PropertyValuesHolder pvh = PropertyValuesHolder.ofObject(property, converter, path);
    678         return ofPropertyValuesHolder(target, pvh);
    679     }
    680 
    681     /**
    682      * Constructs and returns an ObjectAnimator that animates between the sets of values specified
    683      * in <code>PropertyValueHolder</code> objects. This variant should be used when animating
    684      * several properties at once with the same ObjectAnimator, since PropertyValuesHolder allows
    685      * you to associate a set of animation values with a property name.
    686      *
    687      * @param target The object whose property is to be animated. Depending on how the
    688      * PropertyValuesObjects were constructed, the target object should either have the {@link
    689      * android.util.Property} objects used to construct the PropertyValuesHolder objects or (if the
    690      * PropertyValuesHOlder objects were created with property names) the target object should have
    691      * public methods on it called <code>setName()</code>, where <code>name</code> is the name of
    692      * the property passed in as the <code>propertyName</code> parameter for each of the
    693      * PropertyValuesHolder objects.
    694      * @param values A set of PropertyValuesHolder objects whose values will be animated between
    695      * over time.
    696      * @return An ObjectAnimator object that is set up to animate between the given values.
    697      */
    698     @NonNull
    699     public static ObjectAnimator ofPropertyValuesHolder(Object target,
    700             PropertyValuesHolder... values) {
    701         ObjectAnimator anim = new ObjectAnimator();
    702         anim.setTarget(target);
    703         anim.setValues(values);
    704         return anim;
    705     }
    706 
    707     @Override
    708     public void setIntValues(int... values) {
    709         if (mValues == null || mValues.length == 0) {
    710             // No values yet - this animator is being constructed piecemeal. Init the values with
    711             // whatever the current propertyName is
    712             if (mProperty != null) {
    713                 setValues(PropertyValuesHolder.ofInt(mProperty, values));
    714             } else {
    715                 setValues(PropertyValuesHolder.ofInt(mPropertyName, values));
    716             }
    717         } else {
    718             super.setIntValues(values);
    719         }
    720     }
    721 
    722     @Override
    723     public void setFloatValues(float... values) {
    724         if (mValues == null || mValues.length == 0) {
    725             // No values yet - this animator is being constructed piecemeal. Init the values with
    726             // whatever the current propertyName is
    727             if (mProperty != null) {
    728                 setValues(PropertyValuesHolder.ofFloat(mProperty, values));
    729             } else {
    730                 setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
    731             }
    732         } else {
    733             super.setFloatValues(values);
    734         }
    735     }
    736 
    737     @Override
    738     public void setObjectValues(Object... values) {
    739         if (mValues == null || mValues.length == 0) {
    740             // No values yet - this animator is being constructed piecemeal. Init the values with
    741             // whatever the current propertyName is
    742             if (mProperty != null) {
    743                 setValues(PropertyValuesHolder.ofObject(mProperty, (TypeEvaluator) null, values));
    744             } else {
    745                 setValues(PropertyValuesHolder.ofObject(mPropertyName,
    746                         (TypeEvaluator) null, values));
    747             }
    748         } else {
    749             super.setObjectValues(values);
    750         }
    751     }
    752 
    753     /**
    754      * autoCancel controls whether an ObjectAnimator will be canceled automatically
    755      * when any other ObjectAnimator with the same target and properties is started.
    756      * Setting this flag may make it easier to run different animators on the same target
    757      * object without having to keep track of whether there are conflicting animators that
    758      * need to be manually canceled. Canceling animators must have the same exact set of
    759      * target properties, in the same order.
    760      *
    761      * @param cancel Whether future ObjectAnimators with the same target and properties
    762      * as this ObjectAnimator will cause this ObjectAnimator to be canceled.
    763      */
    764     public void setAutoCancel(boolean cancel) {
    765         mAutoCancel = cancel;
    766     }
    767 
    768     private boolean hasSameTargetAndProperties(@Nullable Animator anim) {
    769         if (anim instanceof ObjectAnimator) {
    770             PropertyValuesHolder[] theirValues = ((ObjectAnimator) anim).getValues();
    771             if (((ObjectAnimator) anim).getTarget() == getTarget() &&
    772                     mValues.length == theirValues.length) {
    773                 for (int i = 0; i < mValues.length; ++i) {
    774                     PropertyValuesHolder pvhMine = mValues[i];
    775                     PropertyValuesHolder pvhTheirs = theirValues[i];
    776                     if (pvhMine.getPropertyName() == null ||
    777                             !pvhMine.getPropertyName().equals(pvhTheirs.getPropertyName())) {
    778                         return false;
    779                     }
    780                 }
    781                 return true;
    782             }
    783         }
    784         return false;
    785     }
    786 
    787     @Override
    788     public void start() {
    789         // See if any of the current active/pending animators need to be canceled
    790         AnimationHandler handler = sAnimationHandler.get();
    791         if (handler != null) {
    792             int numAnims = handler.mAnimations.size();
    793             for (int i = numAnims - 1; i >= 0; i--) {
    794                 if (handler.mAnimations.get(i) instanceof ObjectAnimator) {
    795                     ObjectAnimator anim = (ObjectAnimator) handler.mAnimations.get(i);
    796                     if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
    797                         anim.cancel();
    798                     }
    799                 }
    800             }
    801             numAnims = handler.mPendingAnimations.size();
    802             for (int i = numAnims - 1; i >= 0; i--) {
    803                 if (handler.mPendingAnimations.get(i) instanceof ObjectAnimator) {
    804                     ObjectAnimator anim = (ObjectAnimator) handler.mPendingAnimations.get(i);
    805                     if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
    806                         anim.cancel();
    807                     }
    808                 }
    809             }
    810             numAnims = handler.mDelayedAnims.size();
    811             for (int i = numAnims - 1; i >= 0; i--) {
    812                 if (handler.mDelayedAnims.get(i) instanceof ObjectAnimator) {
    813                     ObjectAnimator anim = (ObjectAnimator) handler.mDelayedAnims.get(i);
    814                     if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
    815                         anim.cancel();
    816                     }
    817                 }
    818             }
    819         }
    820         if (DBG) {
    821             Log.d(LOG_TAG, "Anim target, duration: " + getTarget() + ", " + getDuration());
    822             for (int i = 0; i < mValues.length; ++i) {
    823                 PropertyValuesHolder pvh = mValues[i];
    824                 Log.d(LOG_TAG, "   Values[" + i + "]: " +
    825                     pvh.getPropertyName() + ", " + pvh.mKeyframes.getValue(0) + ", " +
    826                     pvh.mKeyframes.getValue(1));
    827             }
    828         }
    829         super.start();
    830     }
    831 
    832     /**
    833      * This function is called immediately before processing the first animation
    834      * frame of an animation. If there is a nonzero <code>startDelay</code>, the
    835      * function is called after that delay ends.
    836      * It takes care of the final initialization steps for the
    837      * animation. This includes setting mEvaluator, if the user has not yet
    838      * set it up, and the setter/getter methods, if the user did not supply
    839      * them.
    840      *
    841      *  <p>Overriders of this method should call the superclass method to cause
    842      *  internal mechanisms to be set up correctly.</p>
    843      */
    844     @Override
    845     void initAnimation() {
    846         if (!mInitialized) {
    847             // mValueType may change due to setter/getter setup; do this before calling super.init(),
    848             // which uses mValueType to set up the default type evaluator.
    849             final Object target = getTarget();
    850             if (target != null) {
    851                 final int numValues = mValues.length;
    852                 for (int i = 0; i < numValues; ++i) {
    853                     mValues[i].setupSetterAndGetter(target);
    854                 }
    855             }
    856             super.initAnimation();
    857         }
    858     }
    859 
    860     /**
    861      * Sets the length of the animation. The default duration is 300 milliseconds.
    862      *
    863      * @param duration The length of the animation, in milliseconds.
    864      * @return ObjectAnimator The object called with setDuration(). This return
    865      * value makes it easier to compose statements together that construct and then set the
    866      * duration, as in
    867      * <code>ObjectAnimator.ofInt(target, propertyName, 0, 10).setDuration(500).start()</code>.
    868      */
    869     @Override
    870     @NonNull
    871     public ObjectAnimator setDuration(long duration) {
    872         super.setDuration(duration);
    873         return this;
    874     }
    875 
    876 
    877     /**
    878      * The target object whose property will be animated by this animation
    879      *
    880      * @return The object being animated
    881      */
    882     @Nullable
    883     public Object getTarget() {
    884         return mTarget == null ? null : mTarget.get();
    885     }
    886 
    887     /**
    888      * Sets the target object whose property will be animated by this animation
    889      *
    890      * @param target The object being animated
    891      */
    892     @Override
    893     public void setTarget(@Nullable Object target) {
    894         final Object oldTarget = getTarget();
    895         if (oldTarget != target) {
    896             mTarget = target == null ? null : new WeakReference<Object>(target);
    897             // New target should cause re-initialization prior to starting
    898             mInitialized = false;
    899         }
    900     }
    901 
    902     @Override
    903     public void setupStartValues() {
    904         initAnimation();
    905 
    906         final Object target = getTarget();
    907         if (target != null) {
    908             final int numValues = mValues.length;
    909             for (int i = 0; i < numValues; ++i) {
    910                 mValues[i].setupStartValue(target);
    911             }
    912         }
    913     }
    914 
    915     @Override
    916     public void setupEndValues() {
    917         initAnimation();
    918 
    919         final Object target = getTarget();
    920         if (target != null) {
    921             final int numValues = mValues.length;
    922             for (int i = 0; i < numValues; ++i) {
    923                 mValues[i].setupEndValue(target);
    924             }
    925         }
    926     }
    927 
    928     /**
    929      * This method is called with the elapsed fraction of the animation during every
    930      * animation frame. This function turns the elapsed fraction into an interpolated fraction
    931      * and then into an animated value (from the evaluator. The function is called mostly during
    932      * animation updates, but it is also called when the <code>end()</code>
    933      * function is called, to set the final value on the property.
    934      *
    935      * <p>Overrides of this method must call the superclass to perform the calculation
    936      * of the animated value.</p>
    937      *
    938      * @param fraction The elapsed fraction of the animation.
    939      */
    940     @Override
    941     void animateValue(float fraction) {
    942         final Object target = getTarget();
    943         if (mTarget != null && target == null) {
    944             // We lost the target reference, cancel and clean up.
    945             cancel();
    946             return;
    947         }
    948 
    949         super.animateValue(fraction);
    950         int numValues = mValues.length;
    951         for (int i = 0; i < numValues; ++i) {
    952             mValues[i].setAnimatedValue(target);
    953         }
    954     }
    955 
    956     @Override
    957     public ObjectAnimator clone() {
    958         final ObjectAnimator anim = (ObjectAnimator) super.clone();
    959         return anim;
    960     }
    961 
    962     @Override
    963     @NonNull
    964     public String toString() {
    965         String returnVal = "ObjectAnimator@" + Integer.toHexString(hashCode()) + ", target " +
    966             getTarget();
    967         if (mValues != null) {
    968             for (int i = 0; i < mValues.length; ++i) {
    969                 returnVal += "\n    " + mValues[i].toString();
    970             }
    971         }
    972         return returnVal;
    973     }
    974 }
    975