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