PropertyValuesHolder.java revision 2794eb3b02e2404d453d3ad22a8a85a138130a07
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.InvocationTargetException; 22import java.lang.reflect.Method; 23import java.util.ArrayList; 24import java.util.HashMap; 25import java.util.concurrent.locks.ReentrantReadWriteLock; 26 27/** 28 * This class holds information about a property and the values that that property 29 * should take on during an animation. PropertyValuesHolder objects can be used to create 30 * animations with ValueAnimator or ObjectAnimator that operate on several different properties 31 * in parallel. 32 */ 33public class PropertyValuesHolder implements Cloneable { 34 35 /** 36 * The name of the property associated with the values. This need not be a real property, 37 * unless this object is being used with ObjectAnimator. But this is the name by which 38 * aniamted values are looked up with getAnimatedValue(String) in ValueAnimator. 39 */ 40 private String mPropertyName; 41 42 /** 43 * The setter function, if needed. ObjectAnimator hands off this functionality to 44 * PropertyValuesHolder, since it holds all of the per-property information. This 45 * property can be manually set via setSetter(). Otherwise, it is automatically 46 * derived when the animation starts in setupSetterAndGetter() if using ObjectAnimator. 47 */ 48 private Method mSetter = null; 49 50 /** 51 * The getter function, if needed. ObjectAnimator hands off this functionality to 52 * PropertyValuesHolder, since it holds all of the per-property information. This 53 * property can be manually set via setSetter(). Otherwise, it is automatically 54 * derived when the animation starts in setupSetterAndGetter() if using ObjectAnimator. 55 * The getter is only derived and used if one of the values is null. 56 */ 57 private Method mGetter = null; 58 59 /** 60 * The type of values supplied. This information is used both in deriving the setter/getter 61 * functions and in deriving the type of TypeEvaluator. 62 */ 63 private Class mValueType; 64 65 /** 66 * The set of keyframes (time/value pairs) that define this animation. 67 */ 68 private KeyframeSet mKeyframeSet = null; 69 70 71 // type evaluators for the three primitive types handled by this implementation 72 private static final TypeEvaluator sIntEvaluator = new IntEvaluator(); 73 private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator(); 74 private static final TypeEvaluator sDoubleEvaluator = new DoubleEvaluator(); 75 76 // We try several different types when searching for appropriate setter/getter functions. 77 // The caller may have supplied values in a type that does not match the setter/getter 78 // functions (such as the integers 0 and 1 to represent floating point values for alpha). 79 // Also, the use of generics in constructors means that we end up with the Object versions 80 // of primitive types (Float vs. float). But most likely, the setter/getter functions 81 // will take primitive types instead. 82 // So we supply an ordered array of other types to try before giving up. 83 private static Class[] FLOAT_VARIANTS = {float.class, Float.class, double.class, int.class, 84 Double.class, Integer.class}; 85 private static Class[] INTEGER_VARIANTS = {int.class, Integer.class, float.class, double.class, 86 Float.class, Double.class}; 87 private static Class[] DOUBLE_VARIANTS = {double.class, Double.class, float.class, int.class, 88 Float.class, Integer.class}; 89 90 // These maps hold all property entries for a particular class. This map 91 // is used to speed up property/setter/getter lookups for a given class/property 92 // combination. No need to use reflection on the combination more than once. 93 private static final HashMap<Class, HashMap<String, Method>> sSetterPropertyMap = 94 new HashMap<Class, HashMap<String, Method>>(); 95 private static final HashMap<Class, HashMap<String, Method>> sGetterPropertyMap = 96 new HashMap<Class, HashMap<String, Method>>(); 97 98 // This lock is used to ensure that only one thread is accessing the property maps 99 // at a time. 100 private ReentrantReadWriteLock propertyMapLock = new ReentrantReadWriteLock(); 101 102 // Used to pass single value to varargs parameter in setter invocation 103 private Object[] mTmpValueArray = new Object[1]; 104 105 /** 106 * The type evaluator used to calculate the animated values. This evaluator is determined 107 * automatically based on the type of the start/end objects passed into the constructor, 108 * but the system only knows about the primitive types int, double, and float. Any other 109 * type will need to set the evaluator to a custom evaluator for that type. 110 */ 111 private TypeEvaluator mEvaluator; 112 113 /** 114 * The value most recently calculated by calculateValue(). This is set during 115 * that function and might be retrieved later either by ValueAnimator.animatedValue() or 116 * by the property-setting logic in ObjectAnimator.animatedValue(). 117 */ 118 private Object mAnimatedValue; 119 120 /** 121 * Internal utility constructor, used by the factory methods to set the property name. 122 * @param propertyName The name of the property for this holder. 123 */ 124 private PropertyValuesHolder(String propertyName) { 125 mPropertyName = propertyName; 126 } 127 128 /** 129 * Constructs and returns a PropertyValuesHolder with a given property name and 130 * set of int values. 131 * @param propertyName The name of the property being animated. 132 * @param values The values that the named property will animate between. 133 * @return PropertyValuesHolder The constructed PropertyValuesHolder object. 134 */ 135 public static PropertyValuesHolder ofInt(String propertyName, int... values) { 136 PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName); 137 pvh.setIntValues(values); 138 Log.v("PVH", "ofFloat: propertyName: " + pvh.mPropertyName); 139 return pvh; 140 } 141 142 /** 143 * Constructs and returns a PropertyValuesHolder with a given property name and 144 * set of float values. 145 * @param propertyName The name of the property being animated. 146 * @param values The values that the named property will animate between. 147 * @return PropertyValuesHolder The constructed PropertyValuesHolder object. 148 */ 149 public static PropertyValuesHolder ofFloat(String propertyName, float... values) { 150 PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName); 151 pvh.setFloatValues(values); 152 Log.v("PVH", "ofFloat: propertyName: " + pvh.mPropertyName); 153 return pvh; 154 } 155 156 /** 157 * Constructs and returns a PropertyValuesHolder with a given property name and 158 * set of double values. 159 * @param propertyName The name of the property being animated. 160 * @param values The values that the named property will animate between. 161 * @return PropertyValuesHolder The constructed PropertyValuesHolder object. 162 */ 163 public static PropertyValuesHolder ofDouble(String propertyName, double... values) { 164 PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName); 165 pvh.setDoubleValues(values); 166 return pvh; 167 } 168 169 /** 170 * Constructs and returns a PropertyValuesHolder with a given property name and 171 * set of long values. 172 * @param propertyName The name of the property being animated. 173 * @param values The values that the named property will animate between. 174 * @return PropertyValuesHolder The constructed PropertyValuesHolder object. 175 */ 176 public static PropertyValuesHolder ofLong(String propertyName, long... values) { 177 PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName); 178 pvh.setLongValues(values); 179 return pvh; 180 } 181 182 /** 183 * Constructs and returns a PropertyValuesHolder with a given property name and 184 * set of Object values. This variant also takes a TypeEvaluator because the system 185 * cannot interpolate between objects of unknown type. 186 * 187 * @param propertyName The name of the property being animated. 188 * @param evaluator A TypeEvaluator that will be called on each animation frame to 189 * provide the ncessry interpolation between the Object values to derive the animated 190 * value. 191 * @param values The values that the named property will animate between. 192 * @return PropertyValuesHolder The constructed PropertyValuesHolder object. 193 */ 194 public static PropertyValuesHolder ofObject(String propertyName, TypeEvaluator evaluator, 195 Object... values) { 196 PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName); 197 pvh.setObjectValues(values); 198 pvh.setEvaluator(evaluator); 199 return pvh; 200 } 201 202 /** 203 * Constructs and returns a PropertyValuesHolder object with the specified property name and set 204 * of values. These values can be of any type, but the type should be consistent so that 205 * an appropriate {@link android.animation.TypeEvaluator} can be found that matches 206 * the common type. 207 * <p>If there is only one value, it is assumed to be the end value of an animation, 208 * and an initial value will be derived, if possible, by calling a getter function 209 * on the object. Also, if any value is null, the value will be filled in when the animation 210 * starts in the same way. This mechanism of automatically getting null values only works 211 * if the PropertyValuesHolder object is used in conjunction 212 * {@link ObjectAnimator}, and with a getter function either 213 * derived automatically from <code>propertyName</code> or set explicitly via 214 * {@link #setGetter(java.lang.reflect.Method)}, since otherwise PropertyValuesHolder has 215 * no way of determining what the value should be. 216 * @param propertyName The name of the property associated with this set of values. This 217 * can be the actual property name to be used when using a ObjectAnimator object, or 218 * just a name used to get animated values, such as if this object is used with an 219 * ValueAnimator object. 220 * @param values The set of values to animate between. 221 */ 222 public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values) { 223 PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName); 224 pvh.setKeyframes(values); 225 return pvh; 226 } 227 228 /** 229 * Set the animated values for this object to this set of ints. 230 * If there is only one value, it is assumed to be the end value of an animation, 231 * and an initial value will be derived, if possible, by calling a getter function 232 * on the object. Also, if any value is null, the value will be filled in when the animation 233 * starts in the same way. This mechanism of automatically getting null values only works 234 * if the PropertyValuesHolder object is used in conjunction 235 * {@link ObjectAnimator}, and with a getter function either 236 * derived automatically from <code>propertyName</code> or set explicitly via 237 * {@link #setGetter(java.lang.reflect.Method)}, since otherwise PropertyValuesHolder has 238 * no way of determining what the value should be. 239 * 240 * @param values One or more values that the animation will animate between. 241 */ 242 public void setIntValues(int... values) { 243 mValueType = int.class; 244 mKeyframeSet = KeyframeSet.ofInt(values); 245 } 246 247 /** 248 * Set the animated values for this object to this set of floats. 249 * If there is only one value, it is assumed to be the end value of an animation, 250 * and an initial value will be derived, if possible, by calling a getter function 251 * on the object. Also, if any value is null, the value will be filled in when the animation 252 * starts in the same way. This mechanism of automatically getting null values only works 253 * if the PropertyValuesHolder object is used in conjunction 254 * {@link ObjectAnimator}, and with a getter function either 255 * derived automatically from <code>propertyName</code> or set explicitly via 256 * {@link #setGetter(java.lang.reflect.Method)}, since otherwise PropertyValuesHolder has 257 * no way of determining what the value should be. 258 * 259 * @param values One or more values that the animation will animate between. 260 */ 261 public void setFloatValues(float... values) { 262 mValueType = float.class; 263 mKeyframeSet = KeyframeSet.ofFloat(values); 264 } 265 266 /** 267 * Set the animated values for this object to this set of doubles. 268 * If there is only one value, it is assumed to be the end value of an animation, 269 * and an initial value will be derived, if possible, by calling a getter function 270 * on the object. Also, if any value is null, the value will be filled in when the animation 271 * starts in the same way. This mechanism of automatically getting null values only works 272 * if the PropertyValuesHolder object is used in conjunction 273 * {@link ObjectAnimator}, and with a getter function either 274 * derived automatically from <code>propertyName</code> or set explicitly via 275 * {@link #setGetter(java.lang.reflect.Method)}, since otherwise PropertyValuesHolder has 276 * no way of determining what the value should be. 277 * 278 * @param values One or more values that the animation will animate between. 279 */ 280 public void setDoubleValues(double... values) { 281 mValueType = double.class; 282 mKeyframeSet = KeyframeSet.ofDouble(values); 283 } 284 285 /** 286 * Set the animated values for this object to this set of longs. 287 * If there is only one value, it is assumed to be the end value of an animation, 288 * and an initial value will be derived, if possible, by calling a getter function 289 * on the object. Also, if any value is null, the value will be filled in when the animation 290 * starts in the same way. This mechanism of automatically getting null values only works 291 * if the PropertyValuesHolder object is used in conjunction 292 * {@link ObjectAnimator}, and with a getter function either 293 * derived automatically from <code>propertyName</code> or set explicitly via 294 * {@link #setGetter(java.lang.reflect.Method)}, since otherwise PropertyValuesHolder has 295 * no way of determining what the value should be. 296 * 297 * @param values One or more values that the animation will animate between. 298 */ 299 public void setLongValues(long... values) { 300 mValueType = long.class; 301 mKeyframeSet = KeyframeSet.ofLong(values); 302 } 303 304 /** 305 * Set the animated values for this object to this set of Keyframes. 306 * 307 * @param values One or more values that the animation will animate between. 308 */ 309 public void setKeyframes(Keyframe... values) { 310 int numKeyframes = values.length; 311 Keyframe keyframes[] = new Keyframe[Math.max(numKeyframes,2)]; 312 mValueType = ((Keyframe)values[0]).getType(); 313 for (int i = 0; i < numKeyframes; ++i) { 314 keyframes[i] = (Keyframe)values[i]; 315 } 316 mKeyframeSet = new KeyframeSet(keyframes); 317 } 318 319 /** 320 * Set the animated values for this object to this set of Objects. 321 * If there is only one value, it is assumed to be the end value of an animation, 322 * and an initial value will be derived, if possible, by calling a getter function 323 * on the object. Also, if any value is null, the value will be filled in when the animation 324 * starts in the same way. This mechanism of automatically getting null values only works 325 * if the PropertyValuesHolder object is used in conjunction 326 * {@link ObjectAnimator}, and with a getter function either 327 * derived automatically from <code>propertyName</code> or set explicitly via 328 * {@link #setGetter(java.lang.reflect.Method)}, since otherwise PropertyValuesHolder has 329 * no way of determining what the value should be. 330 * 331 * @param values One or more values that the animation will animate between. 332 */ 333 public void setObjectValues(Object... values) { 334 mValueType = values[0].getClass(); 335 mKeyframeSet = KeyframeSet.ofObject(values); 336 } 337 338 /** 339 * Determine the setter or getter function using the JavaBeans convention of setFoo or 340 * getFoo for a property named 'foo'. This function figures out what the name of the 341 * function should be and uses reflection to find the Method with that name on the 342 * target object. 343 * 344 * @param targetClass The class to search for the method 345 * @param prefix "set" or "get", depending on whether we need a setter or getter. 346 * @param valueType The type of the parameter (in the case of a setter). This type 347 * is derived from the values set on this PropertyValuesHolder. This type is used as 348 * a first guess at the parameter type, but we check for methods with several different 349 * types to avoid problems with slight mis-matches between supplied values and actual 350 * value types used on the setter. 351 * @return Method the method associated with mPropertyName. 352 */ 353 private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) { 354 // TODO: faster implementation... 355 Log.v("PVH", "getPropertyFunction: class, prefix, valueType, propertyName: " + 356 targetClass + ", " + prefix + ", " + valueType + ", "+ mPropertyName); 357 Method returnVal = null; 358 String firstLetter = mPropertyName.substring(0, 1); 359 String theRest = mPropertyName.substring(1); 360 firstLetter = firstLetter.toUpperCase(); 361 String methodName = prefix + firstLetter + theRest; 362 Class args[] = null; 363 if (valueType == null) { 364 try { 365 returnVal = targetClass.getMethod(methodName, args); 366 } catch (NoSuchMethodException e) { 367 Log.e("PropertyValuesHolder", 368 "Couldn't find no-arg method for property " + mPropertyName + ": " + e); 369 } 370 } else { 371 args = new Class[1]; 372 Class typeVariants[]; 373 if (mValueType.equals(Float.class)) { 374 typeVariants = FLOAT_VARIANTS; 375 } else if (mValueType.equals(Integer.class)) { 376 typeVariants = INTEGER_VARIANTS; 377 } else if (mValueType.equals(Double.class)) { 378 typeVariants = DOUBLE_VARIANTS; 379 } else { 380 typeVariants = new Class[1]; 381 typeVariants[0] = mValueType; 382 } 383 for (Class typeVariant : typeVariants) { 384 args[0] = typeVariant; 385 try { 386 returnVal = targetClass.getMethod(methodName, args); 387 // change the value type to suit 388 mValueType = typeVariant; 389 return returnVal; 390 } catch (NoSuchMethodException e) { 391 // Swallow the error and keep trying other variants 392 } 393 } 394 // If we got here, then no appropriate function was found 395 Log.e("PropertyValuesHolder", 396 "Couldn't find setter/getter for property " + mPropertyName + 397 "with value type "+ mValueType); 398 } 399 400 return returnVal; 401 } 402 403 404 /** 405 * Returns the setter or getter requested. This utility function checks whether the 406 * requested method exists in the propertyMapMap cache. If not, it calls another 407 * utility function to request the Method from the targetClass directly. 408 * @param targetClass The Class on which the requested method should exist. 409 * @param propertyMapMap The cache of setters/getters derived so far. 410 * @param prefix "set" or "get", for the setter or getter. 411 * @param valueType The type of parameter passed into the method (null for getter). 412 * @return Method the method associated with mPropertyName. 413 */ 414 private Method setupSetterOrGetter(Class targetClass, 415 HashMap<Class, HashMap<String, Method>> propertyMapMap, 416 String prefix, Class valueType) { 417 Method setterOrGetter = null; 418 try { 419 // Have to lock property map prior to reading it, to guard against 420 // another thread putting something in there after we've checked it 421 // but before we've added an entry to it 422 // TODO: can we store the setter/getter per Class instead of per Object? 423 propertyMapLock.writeLock().lock(); 424 HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass); 425 if (propertyMap != null) { 426 setterOrGetter = propertyMap.get(mPropertyName); 427 } 428 if (setterOrGetter == null) { 429 setterOrGetter = getPropertyFunction(targetClass, prefix, valueType); 430 if (propertyMap == null) { 431 propertyMap = new HashMap<String, Method>(); 432 propertyMapMap.put(targetClass, propertyMap); 433 } 434 propertyMap.put(mPropertyName, setterOrGetter); 435 } 436 } finally { 437 propertyMapLock.writeLock().unlock(); 438 } 439 return setterOrGetter; 440 } 441 442 /** 443 * Utility function to get the setter from targetClass 444 * @param targetClass The Class on which the requested method should exist. 445 */ 446 private void setupSetter(Class targetClass) { 447 mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", mValueType); 448 } 449 450 /** 451 * Utility function to get the getter from targetClass 452 */ 453 private void setupGetter(Class targetClass) { 454 mGetter = setupSetterOrGetter(targetClass, sGetterPropertyMap, "get", null); 455 } 456 457 /** 458 * Internal function (called from ObjectAnimator) to set up the setter and getter 459 * prior to running the animation. If the setter has not been manually set for this 460 * object, it will be derived automatically given the property name, target object, and 461 * types of values supplied. If no getter has been set, it will be supplied iff any of the 462 * supplied values was null. If there is a null value, then the getter (supplied or derived) 463 * will be called to set those null values to the current value of the property 464 * on the target object. 465 * @param target The object on which the setter (and possibly getter) exist. 466 */ 467 void setupSetterAndGetter(Object target) { 468 Class targetClass = target.getClass(); 469 if (mSetter == null) { 470 setupSetter(targetClass); 471 } 472 for (Keyframe kf : mKeyframeSet.mKeyframes) { 473 if (kf.getValue() == null) { 474 if (mGetter == null) { 475 setupGetter(targetClass); 476 } 477 try { 478 kf.setValue(mGetter.invoke(target)); 479 } catch (InvocationTargetException e) { 480 Log.e("PropertyValuesHolder", e.toString()); 481 } catch (IllegalAccessException e) { 482 Log.e("PropertyValuesHolder", e.toString()); 483 } 484 } 485 } 486 } 487 488 /** 489 * Utility function to set the value stored in a particular Keyframe. The value used is 490 * whatever the value is for the property name specified in the keyframe on the target object. 491 * 492 * @param target The target object from which the current value should be extracted. 493 * @param kf The keyframe which holds the property name and value. 494 */ 495 private void setupValue(Object target, Keyframe kf) { 496 try { 497 if (mGetter == null) { 498 Class targetClass = target.getClass(); 499 setupGetter(targetClass); 500 } 501 kf.setValue(mGetter.invoke(target)); 502 } catch (InvocationTargetException e) { 503 Log.e("PropertyValuesHolder", e.toString()); 504 } catch (IllegalAccessException e) { 505 Log.e("PropertyValuesHolder", e.toString()); 506 } 507 } 508 509 /** 510 * This function is called by ObjectAnimator when setting the start values for an animation. 511 * The start values are set according to the current values in the target object. The 512 * property whose value is extracted is whatever is specified by the propertyName of this 513 * PropertyValuesHolder object. 514 * 515 * @param target The object which holds the start values that should be set. 516 */ 517 void setupStartValue(Object target) { 518 setupValue(target, mKeyframeSet.mKeyframes.get(0)); 519 } 520 521 /** 522 * This function is called by ObjectAnimator when setting the end values for an animation. 523 * The end values are set according to the current values in the target object. The 524 * property whose value is extracted is whatever is specified by the propertyName of this 525 * PropertyValuesHolder object. 526 * 527 * @param target The object which holds the start values that should be set. 528 */ 529 void setupEndValue(Object target) { 530 setupValue(target, mKeyframeSet.mKeyframes.get(mKeyframeSet.mKeyframes.size() - 1)); 531 } 532 533 @Override 534 public PropertyValuesHolder clone() { 535 ArrayList<Keyframe> keyframes = mKeyframeSet.mKeyframes; 536 int numKeyframes = mKeyframeSet.mKeyframes.size(); 537 Keyframe[] newKeyframes = new Keyframe[numKeyframes]; 538 for (int i = 0; i < numKeyframes; ++i) { 539 newKeyframes[i] = keyframes.get(i).clone(); 540 } 541 return PropertyValuesHolder.ofKeyframe(mPropertyName, newKeyframes); 542 } 543 /** 544 * Internal function to set the value on the target object, using the setter set up 545 * earlier on this PropertyValuesHolder object. This function is called by ObjectAnimator 546 * to handle turning the value calculated by ValueAnimator into a value set on the object 547 * according to the name of the property. 548 * @param target The target object on which the value is set 549 */ 550 void setAnimatedValue(Object target) { 551 if (mSetter != null) { 552 try { 553 mTmpValueArray[0] = mAnimatedValue; 554 mSetter.invoke(target, mTmpValueArray); 555 } catch (InvocationTargetException e) { 556 Log.e("PropertyValuesHolder", e.toString()); 557 } catch (IllegalAccessException e) { 558 Log.e("PropertyValuesHolder", e.toString()); 559 } 560 } 561 } 562 563 /** 564 * Internal function, called by ValueAnimator, to set up the TypeEvaluator that will be used 565 * to calculate animated values. 566 */ 567 void init() { 568 if (mEvaluator == null) { 569 mEvaluator = (mValueType == int.class || mValueType == Integer.class) ? sIntEvaluator : 570 (mValueType == double.class || mValueType == Double.class) ? sDoubleEvaluator : 571 sFloatEvaluator; 572 } 573 } 574 575 /** 576 * The TypeEvaluator will the automatically determined based on the type of values 577 * supplied to PropertyValuesHolder. The evaluator can be manually set, however, if so 578 * desired. This may be important in cases where either the type of the values supplied 579 * do not match the way that they should be interpolated between, or if the values 580 * are of a custom type or one not currently understood by the animation system. Currently, 581 * only values of type float, double, and int (and their Object equivalents, Float, Double, 582 * and Integer) are correctly interpolated; all other types require setting a TypeEvaluator. 583 * @param evaluator 584 */ 585 public void setEvaluator(TypeEvaluator evaluator) { 586 mEvaluator = evaluator; 587 } 588 589 /** 590 * Function used to calculate the value according to the evaluator set up for 591 * this PropertyValuesHolder object. This function is called by ValueAnimator.animateValue(). 592 * 593 * @param fraction The elapsed, interpolated fraction of the animation. 594 * @return The calculated value at this point in the animation. 595 */ 596 Object calculateValue(float fraction) { 597 mAnimatedValue = mKeyframeSet.getValue(fraction, mEvaluator); 598 return mAnimatedValue; 599 } 600 601 /** 602 * Sets the <code>Method</code> that is called with the animated values calculated 603 * during the animation. Setting the setter method is an alternative to supplying a 604 * {@link #setPropertyName(String) propertyName} from which the method is derived. This 605 * approach is more direct, and is especially useful when a function must be called that does 606 * not correspond to the convention of <code>setName()</code>. For example, if a function 607 * called <code>offset()</code> is to be called with the animated values, there is no way 608 * to tell <code>ObjectAnimator</code> how to call that function simply through a property 609 * name, so a setter method should be supplied instead. 610 * 611 * <p>Note that the setter function must take the same parameter type as the 612 * <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to 613 * the setter function will fail.</p> 614 * 615 * @param setter The setter method that should be called with the animated values. 616 */ 617 public void setSetter(Method setter) { 618 mSetter = setter; 619 } 620 621 /** 622 * Gets the <code>Method</code> that is called with the animated values calculated 623 * during the animation. 624 */ 625 public Method getSetter() { 626 return mSetter; 627 } 628 629 /** 630 * Sets the <code>Method</code> that is called to get unsupplied <code>valueFrom</code> or 631 * <code>valueTo</code> properties. Setting the getter method is an alternative to supplying a 632 * {@link #setPropertyName(String) propertyName} from which the method is derived. This 633 * approach is more direct, and is especially useful when a function must be called that does 634 * not correspond to the convention of <code>setName()</code>. For example, if a function 635 * called <code>offset()</code> is to be called to get an initial value, there is no way 636 * to tell <code>ObjectAnimator</code> how to call that function simply through a property 637 * name, so a getter method should be supplied instead. 638 * 639 * <p>Note that the getter method is only called whether supplied here or derived 640 * from the property name, if one of <code>valueFrom</code> or <code>valueTo</code> are 641 * null. If both of those values are non-null, then there is no need to get one of the 642 * values and the getter is not called. 643 * 644 * <p>Note that the getter function must return the same parameter type as the 645 * <code>valueFrom</code> and <code>valueTo</code> properties (whichever of them are 646 * non-null), otherwise the call to the getter function will fail.</p> 647 * 648 * @param getter The getter method that should be called to get initial animation values. 649 */ 650 public void setGetter(Method getter) { 651 mGetter = getter; 652 } 653 654 /** 655 * Gets the <code>Method</code> that is called to get unsupplied <code>valueFrom</code> or 656 * <code>valueTo</code> properties. 657 */ 658 public Method getGetter() { 659 return mGetter; 660 } 661 662 /** 663 * Sets the name of the property that will be animated. This name is used to derive 664 * a setter function that will be called to set animated values. 665 * For example, a property name of <code>foo</code> will result 666 * in a call to the function <code>setFoo()</code> on the target object. If either 667 * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will 668 * also be derived and called. 669 * 670 * <p>Note that the setter function derived from this property name 671 * must take the same parameter type as the 672 * <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to 673 * the setter function will fail.</p> 674 * 675 * @param propertyName The name of the property being animated. 676 */ 677 public void setPropertyName(String propertyName) { 678 mPropertyName = propertyName; 679 } 680 681 /** 682 * Gets the name of the property that will be animated. This name will be used to derive 683 * a setter function that will be called to set animated values. 684 * For example, a property name of <code>foo</code> will result 685 * in a call to the function <code>setFoo()</code> on the target object. If either 686 * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will 687 * also be derived and called. 688 */ 689 public String getPropertyName() { 690 return mPropertyName; 691 } 692 693 /** 694 * Internal function, called by ValueAnimator and ObjectAnimator, to retrieve the value 695 * most recently calculated in calculateValue(). 696 * @return 697 */ 698 Object getAnimatedValue() { 699 return mAnimatedValue; 700 } 701}