ObjectAnimator.java revision a18a86b43e40e3c15dcca0ae0148d641be9b25fe
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 17package android.animation; 18 19import android.util.Log; 20 21import java.lang.reflect.Method; 22 23/** 24 * This subclass of {@link ValueAnimator} provides support for animating properties on target objects. 25 * The constructors of this class take parameters to define the target object that will be animated 26 * as well as the name of the property that will be animated. Appropriate set/get functions 27 * are then determined internally and the animation will call these functions as necessary to 28 * animate the property. 29 */ 30public final class ObjectAnimator<T> extends ValueAnimator<T> { 31 32 // The target object on which the property exists, set in the constructor 33 private Object mTarget; 34 35 private String mPropertyName; 36 37 /** 38 * Sets the name of the property that will be animated. This name is used to derive 39 * a setter function that will be called to set animated values. 40 * For example, a property name of <code>foo</code> will result 41 * in a call to the function <code>setFoo()</code> on the target object. If either 42 * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will 43 * also be derived and called. 44 * 45 * <p>Note that the setter function derived from this property name 46 * must take the same parameter type as the 47 * <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to 48 * the setter function will fail.</p> 49 * 50 * <p>If this ObjectAnimator has been set up to animate several properties together, 51 * using more than one PropertyValuesHolder objects, then setting the propertyName simply 52 * sets the propertyName in the first of those PropertyValuesHolder objects.</p> 53 * 54 * @param propertyName The name of the property being animated. 55 */ 56 public void setPropertyName(String propertyName) { 57 if (mValues != null) { 58 // mValues should always be non-null 59 PropertyValuesHolder valuesHolder = mValues[0]; 60 String oldName = valuesHolder.getPropertyName(); 61 valuesHolder.setPropertyName(propertyName); 62 mValuesMap.remove(oldName); 63 mValuesMap.put(propertyName, valuesHolder); 64 } 65 mPropertyName = propertyName; 66 } 67 68 /** 69 * Gets the name of the property that will be animated. This name will be used to derive 70 * a setter function that will be called to set animated values. 71 * For example, a property name of <code>foo</code> will result 72 * in a call to the function <code>setFoo()</code> on the target object. If either 73 * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will 74 * also be derived and called. 75 */ 76 public String getPropertyName() { 77 return mPropertyName; 78 } 79 80 /** 81 * Determine the setter or getter function using the JavaBeans convention of setFoo or 82 * getFoo for a property named 'foo'. This function figures out what the name of the 83 * function should be and uses reflection to find the Method with that name on the 84 * target object. 85 * 86 * @param prefix "set" or "get", depending on whether we need a setter or getter. 87 * @return Method the method associated with mPropertyName. 88 */ 89 private Method getPropertyFunction(String prefix, Class valueType) { 90 // TODO: faster implementation... 91 Method returnVal = null; 92 String firstLetter = mPropertyName.substring(0, 1); 93 String theRest = mPropertyName.substring(1); 94 firstLetter = firstLetter.toUpperCase(); 95 String setterName = prefix + firstLetter + theRest; 96 Class args[] = null; 97 if (valueType != null) { 98 args = new Class[1]; 99 args[0] = valueType; 100 } 101 try { 102 returnVal = mTarget.getClass().getMethod(setterName, args); 103 } catch (NoSuchMethodException e) { 104 Log.e("ObjectAnimator", 105 "Couldn't find setter/getter for property " + mPropertyName + ": " + e); 106 } 107 return returnVal; 108 } 109 110 /** 111 * Creates a new ObjectAnimator object. This default constructor is primarily for 112 * use internally; the other constructors which take parameters are more generally 113 * useful. 114 */ 115 public ObjectAnimator() { 116 } 117 118 /** 119 * A constructor that takes a single property name and set of values. This constructor is 120 * used in the simple case of animating a single property. 121 * 122 * @param duration The length of the animation, in milliseconds. 123 * @param target The object whose property is to be animated. This object should 124 * have a public method on it called <code>setName()</code>, where <code>name</code> is 125 * the value of the <code>propertyName</code> parameter. 126 * @param propertyName The name of the property being animated. 127 * @param values The set of values to animate between. If there is only one value, it 128 * is assumed to be the final value being animated to, and the initial value will be 129 * derived on the fly. 130 */ 131 public ObjectAnimator(long duration, Object target, String propertyName, T...values) { 132 super(duration, (T[]) values); 133 mTarget = target; 134 setPropertyName(propertyName); 135 } 136 137 /** 138 * A constructor that takes <code>PropertyValueHolder</code> values. This constructor should 139 * be used when animating several properties at once with the same ObjectAnimator, since 140 * PropertyValuesHolder allows you to associate a set of animation values with a property 141 * name. 142 * 143 * @param duration The length of the animation, in milliseconds. 144 * @param target The object whose property is to be animated. This object should 145 * have public methods on it called <code>setName()</code>, where <code>name</code> is 146 * the name of the property passed in as the <code>propertyName</code> parameter for 147 * each of the PropertyValuesHolder objects. 148 * @param values The PropertyValuesHolder objects which hold each the property name and values 149 * to animate that property between. 150 */ 151 public ObjectAnimator(long duration, Object target, PropertyValuesHolder...values) { 152 super(duration); 153 setValues(values); 154 mTarget = target; 155 } 156 157 /** 158 * This function is called immediately before processing the first animation 159 * frame of an animation. If there is a nonzero <code>startDelay</code>, the 160 * function is called after that delay ends. 161 * It takes care of the final initialization steps for the 162 * animation. This includes setting mEvaluator, if the user has not yet 163 * set it up, and the setter/getter methods, if the user did not supply 164 * them. 165 * 166 * <p>Overriders of this method should call the superclass method to cause 167 * internal mechanisms to be set up correctly.</p> 168 */ 169 @Override 170 void initAnimation() { 171 if (!mInitialized) { 172 // mValueType may change due to setter/getter setup; do this before calling super.init(), 173 // which uses mValueType to set up the default type evaluator. 174 int numValues = mValues.length; 175 for (int i = 0; i < numValues; ++i) { 176 mValues[i].setupSetterAndGetter(mTarget); 177 } 178 super.initAnimation(); 179 } 180 } 181 182 183 /** 184 * The target object whose property will be animated by this animation 185 * 186 * @return The object being animated 187 */ 188 public Object getTarget() { 189 return mTarget; 190 } 191 192 /** 193 * Sets the target object whose property will be animated by this animation 194 * 195 * @param target The object being animated 196 */ 197 @Override 198 public void setTarget(Object target) { 199 mTarget = target; 200 } 201 202 @Override 203 public void setupStartValues() { 204 initAnimation(); 205 int numValues = mValues.length; 206 for (int i = 0; i < numValues; ++i) { 207 mValues[i].setupStartValue(mTarget); 208 } 209 } 210 211 @Override 212 public void setupEndValues() { 213 initAnimation(); 214 int numValues = mValues.length; 215 for (int i = 0; i < numValues; ++i) { 216 mValues[i].setupEndValue(mTarget); 217 } 218 } 219 220 /** 221 * This method is called with the elapsed fraction of the animation during every 222 * animation frame. This function turns the elapsed fraction into an interpolated fraction 223 * and then into an animated value (from the evaluator. The function is called mostly during 224 * animation updates, but it is also called when the <code>end()</code> 225 * function is called, to set the final value on the property. 226 * 227 * <p>Overrides of this method must call the superclass to perform the calculation 228 * of the animated value.</p> 229 * 230 * @param fraction The elapsed fraction of the animation. 231 */ 232 @Override 233 void animateValue(float fraction) { 234 super.animateValue(fraction); 235 int numValues = mValues.length; 236 for (int i = 0; i < numValues; ++i) { 237 mValues[i].setAnimatedValue(mTarget); 238 } 239 } 240 241 @Override 242 public ObjectAnimator clone() { 243 final ObjectAnimator anim = (ObjectAnimator) super.clone(); 244 return anim; 245 } 246} 247