ValueAnimator.java revision c615c6fc9caca76cd96998f86e1f1e6393aeadbb
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.annotation.CallSuper; 20import android.os.Looper; 21import android.os.Trace; 22import android.util.AndroidRuntimeException; 23import android.view.Choreographer; 24import android.view.animation.AccelerateDecelerateInterpolator; 25import android.view.animation.AnimationUtils; 26import android.view.animation.LinearInterpolator; 27 28import java.util.ArrayList; 29import java.util.HashMap; 30 31/** 32 * This class provides a simple timing engine for running animations 33 * which calculate animated values and set them on target objects. 34 * 35 * <p>There is a single timing pulse that all animations use. It runs in a 36 * custom handler to ensure that property changes happen on the UI thread.</p> 37 * 38 * <p>By default, ValueAnimator uses non-linear time interpolation, via the 39 * {@link AccelerateDecelerateInterpolator} class, which accelerates into and decelerates 40 * out of an animation. This behavior can be changed by calling 41 * {@link ValueAnimator#setInterpolator(TimeInterpolator)}.</p> 42 * 43 * <p>Animators can be created from either code or resource files. Here is an example 44 * of a ValueAnimator resource file:</p> 45 * 46 * {@sample development/samples/ApiDemos/res/anim/animator.xml ValueAnimatorResources} 47 * 48 * <p>It is also possible to use a combination of {@link PropertyValuesHolder} and 49 * {@link Keyframe} resource tags to create a multi-step animation. 50 * Note that you can specify explicit fractional values (from 0 to 1) for 51 * each keyframe to determine when, in the overall duration, the animation should arrive at that 52 * value. Alternatively, you can leave the fractions off and the keyframes will be equally 53 * distributed within the total duration:</p> 54 * 55 * {@sample development/samples/ApiDemos/res/anim/value_animator_pvh_kf.xml 56 * ValueAnimatorKeyframeResources} 57 * 58 * <div class="special reference"> 59 * <h3>Developer Guides</h3> 60 * <p>For more information about animating with {@code ValueAnimator}, read the 61 * <a href="{@docRoot}guide/topics/graphics/prop-animation.html#value-animator">Property 62 * Animation</a> developer guide.</p> 63 * </div> 64 */ 65@SuppressWarnings("unchecked") 66public class ValueAnimator extends Animator { 67 68 /** 69 * Internal constants 70 */ 71 private static float sDurationScale = 1.0f; 72 73 /** 74 * Values used with internal variable mPlayingState to indicate the current state of an 75 * animation. 76 */ 77 static final int STOPPED = 0; // Not yet playing 78 static final int RUNNING = 1; // Playing normally 79 static final int SEEKED = 2; // Seeked to some time value 80 81 /** 82 * Internal variables 83 * NOTE: This object implements the clone() method, making a deep copy of any referenced 84 * objects. As other non-trivial fields are added to this class, make sure to add logic 85 * to clone() to make deep copies of them. 86 */ 87 88 // The first time that the animation's animateFrame() method is called. This time is used to 89 // determine elapsed time (and therefore the elapsed fraction) in subsequent calls 90 // to animateFrame() 91 long mStartTime; 92 93 /** 94 * Set when setCurrentPlayTime() is called. If negative, animation is not currently seeked 95 * to a value. 96 */ 97 float mSeekFraction = -1; 98 99 /** 100 * Set on the next frame after pause() is called, used to calculate a new startTime 101 * or delayStartTime which allows the animator to continue from the point at which 102 * it was paused. If negative, has not yet been set. 103 */ 104 private long mPauseTime; 105 106 /** 107 * Set when an animator is resumed. This triggers logic in the next frame which 108 * actually resumes the animator. 109 */ 110 private boolean mResumed = false; 111 112 113 // The static sAnimationHandler processes the internal timing loop on which all animations 114 // are based 115 /** 116 * @hide 117 */ 118 protected static ThreadLocal<AnimationHandler> sAnimationHandler = 119 new ThreadLocal<AnimationHandler>(); 120 121 // The time interpolator to be used if none is set on the animation 122 private static final TimeInterpolator sDefaultInterpolator = 123 new AccelerateDecelerateInterpolator(); 124 125 /** 126 * Used to indicate whether the animation is currently playing in reverse. This causes the 127 * elapsed fraction to be inverted to calculate the appropriate values. 128 */ 129 private boolean mPlayingBackwards = false; 130 131 /** 132 * Flag to indicate whether this animator is playing in reverse mode, specifically 133 * by being started or interrupted by a call to reverse(). This flag is different than 134 * mPlayingBackwards, which indicates merely whether the current iteration of the 135 * animator is playing in reverse. It is used in corner cases to determine proper end 136 * behavior. 137 */ 138 private boolean mReversing; 139 140 /** 141 * This variable tracks the current iteration that is playing. When mCurrentIteration exceeds the 142 * repeatCount (if repeatCount!=INFINITE), the animation ends 143 */ 144 private int mCurrentIteration = 0; 145 146 /** 147 * Tracks current elapsed/eased fraction, for querying in getAnimatedFraction(). 148 */ 149 private float mCurrentFraction = 0f; 150 151 /** 152 * Tracks whether a startDelay'd animation has begun playing through the startDelay. 153 */ 154 private boolean mStartedDelay = false; 155 156 /** 157 * Tracks the time at which the animation began playing through its startDelay. This is 158 * different from the mStartTime variable, which is used to track when the animation became 159 * active (which is when the startDelay expired and the animation was added to the active 160 * animations list). 161 */ 162 private long mDelayStartTime; 163 164 /** 165 * Flag that represents the current state of the animation. Used to figure out when to start 166 * an animation (if state == STOPPED). Also used to end an animation that 167 * has been cancel()'d or end()'d since the last animation frame. Possible values are 168 * STOPPED, RUNNING, SEEKED. 169 */ 170 int mPlayingState = STOPPED; 171 172 /** 173 * Additional playing state to indicate whether an animator has been start()'d. There is 174 * some lag between a call to start() and the first animation frame. We should still note 175 * that the animation has been started, even if it's first animation frame has not yet 176 * happened, and reflect that state in isRunning(). 177 * Note that delayed animations are different: they are not started until their first 178 * animation frame, which occurs after their delay elapses. 179 */ 180 private boolean mRunning = false; 181 182 /** 183 * Additional playing state to indicate whether an animator has been start()'d, whether or 184 * not there is a nonzero startDelay. 185 */ 186 private boolean mStarted = false; 187 188 /** 189 * Tracks whether we've notified listeners of the onAnimationStart() event. This can be 190 * complex to keep track of since we notify listeners at different times depending on 191 * startDelay and whether start() was called before end(). 192 */ 193 private boolean mStartListenersCalled = false; 194 195 /** 196 * Flag that denotes whether the animation is set up and ready to go. Used to 197 * set up animation that has not yet been started. 198 */ 199 boolean mInitialized = false; 200 201 // 202 // Backing variables 203 // 204 205 // How long the animation should last in ms 206 private long mDuration = (long)(300 * sDurationScale); 207 private long mUnscaledDuration = 300; 208 209 // The amount of time in ms to delay starting the animation after start() is called 210 private long mStartDelay = 0; 211 private long mUnscaledStartDelay = 0; 212 213 // The number of times the animation will repeat. The default is 0, which means the animation 214 // will play only once 215 private int mRepeatCount = 0; 216 217 /** 218 * The type of repetition that will occur when repeatMode is nonzero. RESTART means the 219 * animation will start from the beginning on every new cycle. REVERSE means the animation 220 * will reverse directions on each iteration. 221 */ 222 private int mRepeatMode = RESTART; 223 224 /** 225 * The time interpolator to be used. The elapsed fraction of the animation will be passed 226 * through this interpolator to calculate the interpolated fraction, which is then used to 227 * calculate the animated values. 228 */ 229 private TimeInterpolator mInterpolator = sDefaultInterpolator; 230 231 /** 232 * The set of listeners to be sent events through the life of an animation. 233 */ 234 ArrayList<AnimatorUpdateListener> mUpdateListeners = null; 235 236 /** 237 * The property/value sets being animated. 238 */ 239 PropertyValuesHolder[] mValues; 240 241 /** 242 * A hashmap of the PropertyValuesHolder objects. This map is used to lookup animated values 243 * by property name during calls to getAnimatedValue(String). 244 */ 245 HashMap<String, PropertyValuesHolder> mValuesMap; 246 247 /** 248 * Public constants 249 */ 250 251 /** 252 * When the animation reaches the end and <code>repeatCount</code> is INFINITE 253 * or a positive value, the animation restarts from the beginning. 254 */ 255 public static final int RESTART = 1; 256 /** 257 * When the animation reaches the end and <code>repeatCount</code> is INFINITE 258 * or a positive value, the animation reverses direction on every iteration. 259 */ 260 public static final int REVERSE = 2; 261 /** 262 * This value used used with the {@link #setRepeatCount(int)} property to repeat 263 * the animation indefinitely. 264 */ 265 public static final int INFINITE = -1; 266 267 268 /** 269 * @hide 270 */ 271 public static void setDurationScale(float durationScale) { 272 sDurationScale = durationScale; 273 } 274 275 /** 276 * @hide 277 */ 278 public static float getDurationScale() { 279 return sDurationScale; 280 } 281 282 /** 283 * Creates a new ValueAnimator object. This default constructor is primarily for 284 * use internally; the factory methods which take parameters are more generally 285 * useful. 286 */ 287 public ValueAnimator() { 288 } 289 290 /** 291 * Constructs and returns a ValueAnimator that animates between int values. A single 292 * value implies that that value is the one being animated to. However, this is not typically 293 * useful in a ValueAnimator object because there is no way for the object to determine the 294 * starting value for the animation (unlike ObjectAnimator, which can derive that value 295 * from the target object and property being animated). Therefore, there should typically 296 * be two or more values. 297 * 298 * @param values A set of values that the animation will animate between over time. 299 * @return A ValueAnimator object that is set up to animate between the given values. 300 */ 301 public static ValueAnimator ofInt(int... values) { 302 ValueAnimator anim = new ValueAnimator(); 303 anim.setIntValues(values); 304 return anim; 305 } 306 307 /** 308 * Constructs and returns a ValueAnimator that animates between color values. A single 309 * value implies that that value is the one being animated to. However, this is not typically 310 * useful in a ValueAnimator object because there is no way for the object to determine the 311 * starting value for the animation (unlike ObjectAnimator, which can derive that value 312 * from the target object and property being animated). Therefore, there should typically 313 * be two or more values. 314 * 315 * @param values A set of values that the animation will animate between over time. 316 * @return A ValueAnimator object that is set up to animate between the given values. 317 */ 318 public static ValueAnimator ofArgb(int... values) { 319 ValueAnimator anim = new ValueAnimator(); 320 anim.setIntValues(values); 321 anim.setEvaluator(ArgbEvaluator.getInstance()); 322 return anim; 323 } 324 325 /** 326 * Constructs and returns a ValueAnimator that animates between float values. A single 327 * value implies that that value is the one being animated to. However, this is not typically 328 * useful in a ValueAnimator object because there is no way for the object to determine the 329 * starting value for the animation (unlike ObjectAnimator, which can derive that value 330 * from the target object and property being animated). Therefore, there should typically 331 * be two or more values. 332 * 333 * @param values A set of values that the animation will animate between over time. 334 * @return A ValueAnimator object that is set up to animate between the given values. 335 */ 336 public static ValueAnimator ofFloat(float... values) { 337 ValueAnimator anim = new ValueAnimator(); 338 anim.setFloatValues(values); 339 return anim; 340 } 341 342 /** 343 * Constructs and returns a ValueAnimator that animates between the values 344 * specified in the PropertyValuesHolder objects. 345 * 346 * @param values A set of PropertyValuesHolder objects whose values will be animated 347 * between over time. 348 * @return A ValueAnimator object that is set up to animate between the given values. 349 */ 350 public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values) { 351 ValueAnimator anim = new ValueAnimator(); 352 anim.setValues(values); 353 return anim; 354 } 355 /** 356 * Constructs and returns a ValueAnimator that animates between Object values. A single 357 * value implies that that value is the one being animated to. However, this is not typically 358 * useful in a ValueAnimator object because there is no way for the object to determine the 359 * starting value for the animation (unlike ObjectAnimator, which can derive that value 360 * from the target object and property being animated). Therefore, there should typically 361 * be two or more values. 362 * 363 * <p>Since ValueAnimator does not know how to animate between arbitrary Objects, this 364 * factory method also takes a TypeEvaluator object that the ValueAnimator will use 365 * to perform that interpolation. 366 * 367 * @param evaluator A TypeEvaluator that will be called on each animation frame to 368 * provide the ncessry interpolation between the Object values to derive the animated 369 * value. 370 * @param values A set of values that the animation will animate between over time. 371 * @return A ValueAnimator object that is set up to animate between the given values. 372 */ 373 public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) { 374 ValueAnimator anim = new ValueAnimator(); 375 anim.setObjectValues(values); 376 anim.setEvaluator(evaluator); 377 return anim; 378 } 379 380 /** 381 * Sets int values that will be animated between. A single 382 * value implies that that value is the one being animated to. However, this is not typically 383 * useful in a ValueAnimator object because there is no way for the object to determine the 384 * starting value for the animation (unlike ObjectAnimator, which can derive that value 385 * from the target object and property being animated). Therefore, there should typically 386 * be two or more values. 387 * 388 * <p>If there are already multiple sets of values defined for this ValueAnimator via more 389 * than one PropertyValuesHolder object, this method will set the values for the first 390 * of those objects.</p> 391 * 392 * @param values A set of values that the animation will animate between over time. 393 */ 394 public void setIntValues(int... values) { 395 if (values == null || values.length == 0) { 396 return; 397 } 398 if (mValues == null || mValues.length == 0) { 399 setValues(PropertyValuesHolder.ofInt("", values)); 400 } else { 401 PropertyValuesHolder valuesHolder = mValues[0]; 402 valuesHolder.setIntValues(values); 403 } 404 // New property/values/target should cause re-initialization prior to starting 405 mInitialized = false; 406 } 407 408 /** 409 * Sets float values that will be animated between. A single 410 * value implies that that value is the one being animated to. However, this is not typically 411 * useful in a ValueAnimator object because there is no way for the object to determine the 412 * starting value for the animation (unlike ObjectAnimator, which can derive that value 413 * from the target object and property being animated). Therefore, there should typically 414 * be two or more values. 415 * 416 * <p>If there are already multiple sets of values defined for this ValueAnimator via more 417 * than one PropertyValuesHolder object, this method will set the values for the first 418 * of those objects.</p> 419 * 420 * @param values A set of values that the animation will animate between over time. 421 */ 422 public void setFloatValues(float... values) { 423 if (values == null || values.length == 0) { 424 return; 425 } 426 if (mValues == null || mValues.length == 0) { 427 setValues(PropertyValuesHolder.ofFloat("", values)); 428 } else { 429 PropertyValuesHolder valuesHolder = mValues[0]; 430 valuesHolder.setFloatValues(values); 431 } 432 // New property/values/target should cause re-initialization prior to starting 433 mInitialized = false; 434 } 435 436 /** 437 * Sets the values to animate between for this animation. A single 438 * value implies that that value is the one being animated to. However, this is not typically 439 * useful in a ValueAnimator object because there is no way for the object to determine the 440 * starting value for the animation (unlike ObjectAnimator, which can derive that value 441 * from the target object and property being animated). Therefore, there should typically 442 * be two or more values. 443 * 444 * <p>If there are already multiple sets of values defined for this ValueAnimator via more 445 * than one PropertyValuesHolder object, this method will set the values for the first 446 * of those objects.</p> 447 * 448 * <p>There should be a TypeEvaluator set on the ValueAnimator that knows how to interpolate 449 * between these value objects. ValueAnimator only knows how to interpolate between the 450 * primitive types specified in the other setValues() methods.</p> 451 * 452 * @param values The set of values to animate between. 453 */ 454 public void setObjectValues(Object... values) { 455 if (values == null || values.length == 0) { 456 return; 457 } 458 if (mValues == null || mValues.length == 0) { 459 setValues(PropertyValuesHolder.ofObject("", null, values)); 460 } else { 461 PropertyValuesHolder valuesHolder = mValues[0]; 462 valuesHolder.setObjectValues(values); 463 } 464 // New property/values/target should cause re-initialization prior to starting 465 mInitialized = false; 466 } 467 468 /** 469 * Sets the values, per property, being animated between. This function is called internally 470 * by the constructors of ValueAnimator that take a list of values. But a ValueAnimator can 471 * be constructed without values and this method can be called to set the values manually 472 * instead. 473 * 474 * @param values The set of values, per property, being animated between. 475 */ 476 public void setValues(PropertyValuesHolder... values) { 477 int numValues = values.length; 478 mValues = values; 479 mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues); 480 for (int i = 0; i < numValues; ++i) { 481 PropertyValuesHolder valuesHolder = values[i]; 482 mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder); 483 } 484 // New property/values/target should cause re-initialization prior to starting 485 mInitialized = false; 486 } 487 488 /** 489 * Returns the values that this ValueAnimator animates between. These values are stored in 490 * PropertyValuesHolder objects, even if the ValueAnimator was created with a simple list 491 * of value objects instead. 492 * 493 * @return PropertyValuesHolder[] An array of PropertyValuesHolder objects which hold the 494 * values, per property, that define the animation. 495 */ 496 public PropertyValuesHolder[] getValues() { 497 return mValues; 498 } 499 500 /** 501 * This function is called immediately before processing the first animation 502 * frame of an animation. If there is a nonzero <code>startDelay</code>, the 503 * function is called after that delay ends. 504 * It takes care of the final initialization steps for the 505 * animation. 506 * 507 * <p>Overrides of this method should call the superclass method to ensure 508 * that internal mechanisms for the animation are set up correctly.</p> 509 */ 510 @CallSuper 511 void initAnimation() { 512 if (!mInitialized) { 513 int numValues = mValues.length; 514 for (int i = 0; i < numValues; ++i) { 515 mValues[i].init(); 516 } 517 mInitialized = true; 518 } 519 } 520 521 522 /** 523 * Sets the length of the animation. The default duration is 300 milliseconds. 524 * 525 * @param duration The length of the animation, in milliseconds. This value cannot 526 * be negative. 527 * @return ValueAnimator The object called with setDuration(). This return 528 * value makes it easier to compose statements together that construct and then set the 529 * duration, as in <code>ValueAnimator.ofInt(0, 10).setDuration(500).start()</code>. 530 */ 531 public ValueAnimator setDuration(long duration) { 532 if (duration < 0) { 533 throw new IllegalArgumentException("Animators cannot have negative duration: " + 534 duration); 535 } 536 mUnscaledDuration = duration; 537 updateScaledDuration(); 538 return this; 539 } 540 541 private void updateScaledDuration() { 542 mDuration = (long)(mUnscaledDuration * sDurationScale); 543 } 544 545 /** 546 * Gets the length of the animation. The default duration is 300 milliseconds. 547 * 548 * @return The length of the animation, in milliseconds. 549 */ 550 public long getDuration() { 551 return mUnscaledDuration; 552 } 553 554 /** 555 * Sets the position of the animation to the specified point in time. This time should 556 * be between 0 and the total duration of the animation, including any repetition. If 557 * the animation has not yet been started, then it will not advance forward after it is 558 * set to this time; it will simply set the time to this value and perform any appropriate 559 * actions based on that time. If the animation is already running, then setCurrentPlayTime() 560 * will set the current playing time to this value and continue playing from that point. 561 * 562 * @param playTime The time, in milliseconds, to which the animation is advanced or rewound. 563 */ 564 public void setCurrentPlayTime(long playTime) { 565 float fraction = mUnscaledDuration > 0 ? (float) playTime / mUnscaledDuration : 1; 566 setCurrentFraction(fraction); 567 } 568 569 /** 570 * Sets the position of the animation to the specified fraction. This fraction should 571 * be between 0 and the total fraction of the animation, including any repetition. That is, 572 * a fraction of 0 will position the animation at the beginning, a value of 1 at the end, 573 * and a value of 2 at the end of a reversing animator that repeats once. If 574 * the animation has not yet been started, then it will not advance forward after it is 575 * set to this fraction; it will simply set the fraction to this value and perform any 576 * appropriate actions based on that fraction. If the animation is already running, then 577 * setCurrentFraction() will set the current fraction to this value and continue 578 * playing from that point. {@link Animator.AnimatorListener} events are not called 579 * due to changing the fraction; those events are only processed while the animation 580 * is running. 581 * 582 * @param fraction The fraction to which the animation is advanced or rewound. Values 583 * outside the range of 0 to the maximum fraction for the animator will be clamped to 584 * the correct range. 585 */ 586 public void setCurrentFraction(float fraction) { 587 initAnimation(); 588 if (fraction < 0) { 589 fraction = 0; 590 } 591 int iteration = (int) fraction; 592 if (fraction == 1) { 593 iteration -= 1; 594 } else if (fraction > 1) { 595 if (iteration < (mRepeatCount + 1) || mRepeatCount == INFINITE) { 596 if (mRepeatMode == REVERSE) { 597 mPlayingBackwards = (iteration % 2) != 0; 598 } 599 fraction = fraction % 1f; 600 } else { 601 fraction = 1; 602 iteration -= 1; 603 } 604 } else { 605 mPlayingBackwards = mReversing; 606 } 607 mCurrentIteration = iteration; 608 long seekTime = (long) (mDuration * fraction); 609 long currentTime = AnimationUtils.currentAnimationTimeMillis(); 610 mStartTime = currentTime - seekTime; 611 if (mPlayingState != RUNNING) { 612 mSeekFraction = fraction; 613 mPlayingState = SEEKED; 614 } 615 if (mPlayingBackwards) { 616 fraction = 1f - fraction; 617 } 618 animateValue(fraction); 619 } 620 621 /** 622 * Gets the current position of the animation in time, which is equal to the current 623 * time minus the time that the animation started. An animation that is not yet started will 624 * return a value of zero. 625 * 626 * @return The current position in time of the animation. 627 */ 628 public long getCurrentPlayTime() { 629 if (!mInitialized || mPlayingState == STOPPED) { 630 return 0; 631 } 632 return AnimationUtils.currentAnimationTimeMillis() - mStartTime; 633 } 634 635 /** 636 * This custom, static handler handles the timing pulse that is shared by 637 * all active animations. This approach ensures that the setting of animation 638 * values will happen on the UI thread and that all animations will share 639 * the same times for calculating their values, which makes synchronizing 640 * animations possible. 641 * 642 * The handler uses the Choreographer for executing periodic callbacks. 643 * 644 * @hide 645 */ 646 @SuppressWarnings("unchecked") 647 protected static class AnimationHandler implements Runnable { 648 // The per-thread list of all active animations 649 /** @hide */ 650 protected final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>(); 651 652 // Used in doAnimationFrame() to avoid concurrent modifications of mAnimations 653 private final ArrayList<ValueAnimator> mTmpAnimations = new ArrayList<ValueAnimator>(); 654 655 // The per-thread set of animations to be started on the next animation frame 656 /** @hide */ 657 protected final ArrayList<ValueAnimator> mPendingAnimations = new ArrayList<ValueAnimator>(); 658 659 /** 660 * Internal per-thread collections used to avoid set collisions as animations start and end 661 * while being processed. 662 * @hide 663 */ 664 protected final ArrayList<ValueAnimator> mDelayedAnims = new ArrayList<ValueAnimator>(); 665 private final ArrayList<ValueAnimator> mEndingAnims = new ArrayList<ValueAnimator>(); 666 private final ArrayList<ValueAnimator> mReadyAnims = new ArrayList<ValueAnimator>(); 667 668 private final Choreographer mChoreographer; 669 private boolean mAnimationScheduled; 670 671 private AnimationHandler() { 672 mChoreographer = Choreographer.getInstance(); 673 } 674 675 /** 676 * Start animating on the next frame. 677 */ 678 public void start() { 679 scheduleAnimation(); 680 } 681 682 private void doAnimationFrame(long frameTime) { 683 // mPendingAnimations holds any animations that have requested to be started 684 // We're going to clear mPendingAnimations, but starting animation may 685 // cause more to be added to the pending list (for example, if one animation 686 // starting triggers another starting). So we loop until mPendingAnimations 687 // is empty. 688 while (mPendingAnimations.size() > 0) { 689 ArrayList<ValueAnimator> pendingCopy = 690 (ArrayList<ValueAnimator>) mPendingAnimations.clone(); 691 mPendingAnimations.clear(); 692 int count = pendingCopy.size(); 693 for (int i = 0; i < count; ++i) { 694 ValueAnimator anim = pendingCopy.get(i); 695 // If the animation has a startDelay, place it on the delayed list 696 if (anim.mStartDelay == 0) { 697 anim.startAnimation(this); 698 } else { 699 mDelayedAnims.add(anim); 700 } 701 } 702 } 703 // Next, process animations currently sitting on the delayed queue, adding 704 // them to the active animations if they are ready 705 int numDelayedAnims = mDelayedAnims.size(); 706 for (int i = 0; i < numDelayedAnims; ++i) { 707 ValueAnimator anim = mDelayedAnims.get(i); 708 if (anim.delayedAnimationFrame(frameTime)) { 709 mReadyAnims.add(anim); 710 } 711 } 712 int numReadyAnims = mReadyAnims.size(); 713 if (numReadyAnims > 0) { 714 for (int i = 0; i < numReadyAnims; ++i) { 715 ValueAnimator anim = mReadyAnims.get(i); 716 anim.startAnimation(this); 717 anim.mRunning = true; 718 mDelayedAnims.remove(anim); 719 } 720 mReadyAnims.clear(); 721 } 722 723 // Now process all active animations. The return value from animationFrame() 724 // tells the handler whether it should now be ended 725 int numAnims = mAnimations.size(); 726 for (int i = 0; i < numAnims; ++i) { 727 mTmpAnimations.add(mAnimations.get(i)); 728 } 729 for (int i = 0; i < numAnims; ++i) { 730 ValueAnimator anim = mTmpAnimations.get(i); 731 if (mAnimations.contains(anim) && anim.doAnimationFrame(frameTime)) { 732 mEndingAnims.add(anim); 733 } 734 } 735 mTmpAnimations.clear(); 736 if (mEndingAnims.size() > 0) { 737 for (int i = 0; i < mEndingAnims.size(); ++i) { 738 mEndingAnims.get(i).endAnimation(this); 739 } 740 mEndingAnims.clear(); 741 } 742 743 // If there are still active or delayed animations, schedule a future call to 744 // onAnimate to process the next frame of the animations. 745 if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) { 746 scheduleAnimation(); 747 } 748 } 749 750 // Called by the Choreographer. 751 @Override 752 public void run() { 753 mAnimationScheduled = false; 754 doAnimationFrame(mChoreographer.getFrameTime()); 755 } 756 757 private void scheduleAnimation() { 758 if (!mAnimationScheduled) { 759 mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null); 760 mAnimationScheduled = true; 761 } 762 } 763 } 764 765 /** 766 * The amount of time, in milliseconds, to delay starting the animation after 767 * {@link #start()} is called. 768 * 769 * @return the number of milliseconds to delay running the animation 770 */ 771 public long getStartDelay() { 772 return mUnscaledStartDelay; 773 } 774 775 /** 776 * The amount of time, in milliseconds, to delay starting the animation after 777 * {@link #start()} is called. 778 779 * @param startDelay The amount of the delay, in milliseconds 780 */ 781 public void setStartDelay(long startDelay) { 782 this.mStartDelay = (long)(startDelay * sDurationScale); 783 mUnscaledStartDelay = startDelay; 784 } 785 786 /** 787 * The amount of time, in milliseconds, between each frame of the animation. This is a 788 * requested time that the animation will attempt to honor, but the actual delay between 789 * frames may be different, depending on system load and capabilities. This is a static 790 * function because the same delay will be applied to all animations, since they are all 791 * run off of a single timing loop. 792 * 793 * The frame delay may be ignored when the animation system uses an external timing 794 * source, such as the display refresh rate (vsync), to govern animations. 795 * 796 * @return the requested time between frames, in milliseconds 797 */ 798 public static long getFrameDelay() { 799 return Choreographer.getFrameDelay(); 800 } 801 802 /** 803 * The amount of time, in milliseconds, between each frame of the animation. This is a 804 * requested time that the animation will attempt to honor, but the actual delay between 805 * frames may be different, depending on system load and capabilities. This is a static 806 * function because the same delay will be applied to all animations, since they are all 807 * run off of a single timing loop. 808 * 809 * The frame delay may be ignored when the animation system uses an external timing 810 * source, such as the display refresh rate (vsync), to govern animations. 811 * 812 * @param frameDelay the requested time between frames, in milliseconds 813 */ 814 public static void setFrameDelay(long frameDelay) { 815 Choreographer.setFrameDelay(frameDelay); 816 } 817 818 /** 819 * The most recent value calculated by this <code>ValueAnimator</code> when there is just one 820 * property being animated. This value is only sensible while the animation is running. The main 821 * purpose for this read-only property is to retrieve the value from the <code>ValueAnimator</code> 822 * during a call to {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which 823 * is called during each animation frame, immediately after the value is calculated. 824 * 825 * @return animatedValue The value most recently calculated by this <code>ValueAnimator</code> for 826 * the single property being animated. If there are several properties being animated 827 * (specified by several PropertyValuesHolder objects in the constructor), this function 828 * returns the animated value for the first of those objects. 829 */ 830 public Object getAnimatedValue() { 831 if (mValues != null && mValues.length > 0) { 832 return mValues[0].getAnimatedValue(); 833 } 834 // Shouldn't get here; should always have values unless ValueAnimator was set up wrong 835 return null; 836 } 837 838 /** 839 * The most recent value calculated by this <code>ValueAnimator</code> for <code>propertyName</code>. 840 * The main purpose for this read-only property is to retrieve the value from the 841 * <code>ValueAnimator</code> during a call to 842 * {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which 843 * is called during each animation frame, immediately after the value is calculated. 844 * 845 * @return animatedValue The value most recently calculated for the named property 846 * by this <code>ValueAnimator</code>. 847 */ 848 public Object getAnimatedValue(String propertyName) { 849 PropertyValuesHolder valuesHolder = mValuesMap.get(propertyName); 850 if (valuesHolder != null) { 851 return valuesHolder.getAnimatedValue(); 852 } else { 853 // At least avoid crashing if called with bogus propertyName 854 return null; 855 } 856 } 857 858 /** 859 * Sets how many times the animation should be repeated. If the repeat 860 * count is 0, the animation is never repeated. If the repeat count is 861 * greater than 0 or {@link #INFINITE}, the repeat mode will be taken 862 * into account. The repeat count is 0 by default. 863 * 864 * @param value the number of times the animation should be repeated 865 */ 866 public void setRepeatCount(int value) { 867 mRepeatCount = value; 868 } 869 /** 870 * Defines how many times the animation should repeat. The default value 871 * is 0. 872 * 873 * @return the number of times the animation should repeat, or {@link #INFINITE} 874 */ 875 public int getRepeatCount() { 876 return mRepeatCount; 877 } 878 879 /** 880 * Defines what this animation should do when it reaches the end. This 881 * setting is applied only when the repeat count is either greater than 882 * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}. 883 * 884 * @param value {@link #RESTART} or {@link #REVERSE} 885 */ 886 public void setRepeatMode(int value) { 887 mRepeatMode = value; 888 } 889 890 /** 891 * Defines what this animation should do when it reaches the end. 892 * 893 * @return either one of {@link #REVERSE} or {@link #RESTART} 894 */ 895 public int getRepeatMode() { 896 return mRepeatMode; 897 } 898 899 /** 900 * Adds a listener to the set of listeners that are sent update events through the life of 901 * an animation. This method is called on all listeners for every frame of the animation, 902 * after the values for the animation have been calculated. 903 * 904 * @param listener the listener to be added to the current set of listeners for this animation. 905 */ 906 public void addUpdateListener(AnimatorUpdateListener listener) { 907 if (mUpdateListeners == null) { 908 mUpdateListeners = new ArrayList<AnimatorUpdateListener>(); 909 } 910 mUpdateListeners.add(listener); 911 } 912 913 /** 914 * Removes all listeners from the set listening to frame updates for this animation. 915 */ 916 public void removeAllUpdateListeners() { 917 if (mUpdateListeners == null) { 918 return; 919 } 920 mUpdateListeners.clear(); 921 mUpdateListeners = null; 922 } 923 924 /** 925 * Removes a listener from the set listening to frame updates for this animation. 926 * 927 * @param listener the listener to be removed from the current set of update listeners 928 * for this animation. 929 */ 930 public void removeUpdateListener(AnimatorUpdateListener listener) { 931 if (mUpdateListeners == null) { 932 return; 933 } 934 mUpdateListeners.remove(listener); 935 if (mUpdateListeners.size() == 0) { 936 mUpdateListeners = null; 937 } 938 } 939 940 941 /** 942 * The time interpolator used in calculating the elapsed fraction of this animation. The 943 * interpolator determines whether the animation runs with linear or non-linear motion, 944 * such as acceleration and deceleration. The default value is 945 * {@link android.view.animation.AccelerateDecelerateInterpolator} 946 * 947 * @param value the interpolator to be used by this animation. A value of <code>null</code> 948 * will result in linear interpolation. 949 */ 950 @Override 951 public void setInterpolator(TimeInterpolator value) { 952 if (value != null) { 953 mInterpolator = value; 954 } else { 955 mInterpolator = new LinearInterpolator(); 956 } 957 } 958 959 /** 960 * Returns the timing interpolator that this ValueAnimator uses. 961 * 962 * @return The timing interpolator for this ValueAnimator. 963 */ 964 @Override 965 public TimeInterpolator getInterpolator() { 966 return mInterpolator; 967 } 968 969 /** 970 * The type evaluator to be used when calculating the animated values of this animation. 971 * The system will automatically assign a float or int evaluator based on the type 972 * of <code>startValue</code> and <code>endValue</code> in the constructor. But if these values 973 * are not one of these primitive types, or if different evaluation is desired (such as is 974 * necessary with int values that represent colors), a custom evaluator needs to be assigned. 975 * For example, when running an animation on color values, the {@link ArgbEvaluator} 976 * should be used to get correct RGB color interpolation. 977 * 978 * <p>If this ValueAnimator has only one set of values being animated between, this evaluator 979 * will be used for that set. If there are several sets of values being animated, which is 980 * the case if PropertyValuesHolder objects were set on the ValueAnimator, then the evaluator 981 * is assigned just to the first PropertyValuesHolder object.</p> 982 * 983 * @param value the evaluator to be used this animation 984 */ 985 public void setEvaluator(TypeEvaluator value) { 986 if (value != null && mValues != null && mValues.length > 0) { 987 mValues[0].setEvaluator(value); 988 } 989 } 990 991 private void notifyStartListeners() { 992 if (mListeners != null && !mStartListenersCalled) { 993 ArrayList<AnimatorListener> tmpListeners = 994 (ArrayList<AnimatorListener>) mListeners.clone(); 995 int numListeners = tmpListeners.size(); 996 for (int i = 0; i < numListeners; ++i) { 997 tmpListeners.get(i).onAnimationStart(this); 998 } 999 } 1000 mStartListenersCalled = true; 1001 } 1002 1003 /** 1004 * Start the animation playing. This version of start() takes a boolean flag that indicates 1005 * whether the animation should play in reverse. The flag is usually false, but may be set 1006 * to true if called from the reverse() method. 1007 * 1008 * <p>The animation started by calling this method will be run on the thread that called 1009 * this method. This thread should have a Looper on it (a runtime exception will be thrown if 1010 * this is not the case). Also, if the animation will animate 1011 * properties of objects in the view hierarchy, then the calling thread should be the UI 1012 * thread for that view hierarchy.</p> 1013 * 1014 * @param playBackwards Whether the ValueAnimator should start playing in reverse. 1015 */ 1016 private void start(boolean playBackwards) { 1017 if (Looper.myLooper() == null) { 1018 throw new AndroidRuntimeException("Animators may only be run on Looper threads"); 1019 } 1020 mReversing = playBackwards; 1021 mPlayingBackwards = playBackwards; 1022 if (playBackwards && mSeekFraction != -1) { 1023 if (mSeekFraction == 0 && mCurrentIteration == 0) { 1024 // special case: reversing from seek-to-0 should act as if not seeked at all 1025 mSeekFraction = 0; 1026 } else if (mRepeatCount == INFINITE) { 1027 mSeekFraction = 1 - (mSeekFraction % 1); 1028 } else { 1029 mSeekFraction = 1 + mRepeatCount - (mCurrentIteration + mSeekFraction); 1030 } 1031 mCurrentIteration = (int) mSeekFraction; 1032 mSeekFraction = mSeekFraction % 1; 1033 } 1034 if (mCurrentIteration > 0 && mRepeatMode == REVERSE && 1035 (mCurrentIteration < (mRepeatCount + 1) || mRepeatCount == INFINITE)) { 1036 // if we were seeked to some other iteration in a reversing animator, 1037 // figure out the correct direction to start playing based on the iteration 1038 if (playBackwards) { 1039 mPlayingBackwards = (mCurrentIteration % 2) == 0; 1040 } else { 1041 mPlayingBackwards = (mCurrentIteration % 2) != 0; 1042 } 1043 } 1044 int prevPlayingState = mPlayingState; 1045 mPlayingState = STOPPED; 1046 mStarted = true; 1047 mStartedDelay = false; 1048 mPaused = false; 1049 updateScaledDuration(); // in case the scale factor has changed since creation time 1050 AnimationHandler animationHandler = getOrCreateAnimationHandler(); 1051 animationHandler.mPendingAnimations.add(this); 1052 if (mStartDelay == 0) { 1053 // This sets the initial value of the animation, prior to actually starting it running 1054 if (prevPlayingState != SEEKED) { 1055 setCurrentPlayTime(0); 1056 } 1057 mPlayingState = STOPPED; 1058 mRunning = true; 1059 notifyStartListeners(); 1060 } 1061 animationHandler.start(); 1062 } 1063 1064 @Override 1065 public void start() { 1066 start(false); 1067 } 1068 1069 @Override 1070 public void cancel() { 1071 // Only cancel if the animation is actually running or has been started and is about 1072 // to run 1073 AnimationHandler handler = getOrCreateAnimationHandler(); 1074 if (mPlayingState != STOPPED 1075 || handler.mPendingAnimations.contains(this) 1076 || handler.mDelayedAnims.contains(this)) { 1077 // Only notify listeners if the animator has actually started 1078 if ((mStarted || mRunning) && mListeners != null) { 1079 if (!mRunning) { 1080 // If it's not yet running, then start listeners weren't called. Call them now. 1081 notifyStartListeners(); 1082 } 1083 ArrayList<AnimatorListener> tmpListeners = 1084 (ArrayList<AnimatorListener>) mListeners.clone(); 1085 for (AnimatorListener listener : tmpListeners) { 1086 listener.onAnimationCancel(this); 1087 } 1088 } 1089 endAnimation(handler); 1090 } 1091 } 1092 1093 @Override 1094 public void end() { 1095 AnimationHandler handler = getOrCreateAnimationHandler(); 1096 if (!handler.mAnimations.contains(this) && !handler.mPendingAnimations.contains(this)) { 1097 // Special case if the animation has not yet started; get it ready for ending 1098 mStartedDelay = false; 1099 startAnimation(handler); 1100 mStarted = true; 1101 } else if (!mInitialized) { 1102 initAnimation(); 1103 } 1104 animateValue(mPlayingBackwards ? 0f : 1f); 1105 endAnimation(handler); 1106 } 1107 1108 @Override 1109 public void resume() { 1110 if (mPaused) { 1111 mResumed = true; 1112 } 1113 super.resume(); 1114 } 1115 1116 @Override 1117 public void pause() { 1118 boolean previouslyPaused = mPaused; 1119 super.pause(); 1120 if (!previouslyPaused && mPaused) { 1121 mPauseTime = -1; 1122 mResumed = false; 1123 } 1124 } 1125 1126 @Override 1127 public boolean isRunning() { 1128 return (mPlayingState == RUNNING || mRunning); 1129 } 1130 1131 @Override 1132 public boolean isStarted() { 1133 return mStarted; 1134 } 1135 1136 /** 1137 * Plays the ValueAnimator in reverse. If the animation is already running, 1138 * it will stop itself and play backwards from the point reached when reverse was called. 1139 * If the animation is not currently running, then it will start from the end and 1140 * play backwards. This behavior is only set for the current animation; future playing 1141 * of the animation will use the default behavior of playing forward. 1142 */ 1143 @Override 1144 public void reverse() { 1145 mPlayingBackwards = !mPlayingBackwards; 1146 if (mPlayingState == RUNNING) { 1147 long currentTime = AnimationUtils.currentAnimationTimeMillis(); 1148 long currentPlayTime = currentTime - mStartTime; 1149 long timeLeft = mDuration - currentPlayTime; 1150 mStartTime = currentTime - timeLeft; 1151 mReversing = !mReversing; 1152 } else if (mStarted) { 1153 end(); 1154 } else { 1155 start(true); 1156 } 1157 } 1158 1159 /** 1160 * @hide 1161 */ 1162 @Override 1163 public boolean canReverse() { 1164 return true; 1165 } 1166 1167 /** 1168 * Called internally to end an animation by removing it from the animations list. Must be 1169 * called on the UI thread. 1170 * @hide 1171 */ 1172 protected void endAnimation(AnimationHandler handler) { 1173 handler.mAnimations.remove(this); 1174 handler.mPendingAnimations.remove(this); 1175 handler.mDelayedAnims.remove(this); 1176 mPlayingState = STOPPED; 1177 mPaused = false; 1178 if ((mStarted || mRunning) && mListeners != null) { 1179 if (!mRunning) { 1180 // If it's not yet running, then start listeners weren't called. Call them now. 1181 notifyStartListeners(); 1182 } 1183 ArrayList<AnimatorListener> tmpListeners = 1184 (ArrayList<AnimatorListener>) mListeners.clone(); 1185 int numListeners = tmpListeners.size(); 1186 for (int i = 0; i < numListeners; ++i) { 1187 tmpListeners.get(i).onAnimationEnd(this); 1188 } 1189 } 1190 mRunning = false; 1191 mStarted = false; 1192 mStartListenersCalled = false; 1193 mPlayingBackwards = false; 1194 mReversing = false; 1195 mCurrentIteration = 0; 1196 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 1197 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(), 1198 System.identityHashCode(this)); 1199 } 1200 } 1201 1202 /** 1203 * Called internally to start an animation by adding it to the active animations list. Must be 1204 * called on the UI thread. 1205 */ 1206 private void startAnimation(AnimationHandler handler) { 1207 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 1208 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, getNameForTrace(), 1209 System.identityHashCode(this)); 1210 } 1211 initAnimation(); 1212 handler.mAnimations.add(this); 1213 if (mStartDelay > 0 && mListeners != null) { 1214 // Listeners were already notified in start() if startDelay is 0; this is 1215 // just for delayed animations 1216 notifyStartListeners(); 1217 } 1218 } 1219 1220 /** 1221 * Returns the name of this animator for debugging purposes. 1222 */ 1223 String getNameForTrace() { 1224 return "animator"; 1225 } 1226 1227 1228 /** 1229 * Internal function called to process an animation frame on an animation that is currently 1230 * sleeping through its <code>startDelay</code> phase. The return value indicates whether it 1231 * should be woken up and put on the active animations queue. 1232 * 1233 * @param currentTime The current animation time, used to calculate whether the animation 1234 * has exceeded its <code>startDelay</code> and should be started. 1235 * @return True if the animation's <code>startDelay</code> has been exceeded and the animation 1236 * should be added to the set of active animations. 1237 */ 1238 private boolean delayedAnimationFrame(long currentTime) { 1239 if (!mStartedDelay) { 1240 mStartedDelay = true; 1241 mDelayStartTime = currentTime; 1242 } 1243 if (mPaused) { 1244 if (mPauseTime < 0) { 1245 mPauseTime = currentTime; 1246 } 1247 return false; 1248 } else if (mResumed) { 1249 mResumed = false; 1250 if (mPauseTime > 0) { 1251 // Offset by the duration that the animation was paused 1252 mDelayStartTime += (currentTime - mPauseTime); 1253 } 1254 } 1255 long deltaTime = currentTime - mDelayStartTime; 1256 if (deltaTime > mStartDelay) { 1257 // startDelay ended - start the anim and record the 1258 // mStartTime appropriately 1259 mStartTime = currentTime - (deltaTime - mStartDelay); 1260 mPlayingState = RUNNING; 1261 return true; 1262 } 1263 return false; 1264 } 1265 1266 /** 1267 * This internal function processes a single animation frame for a given animation. The 1268 * currentTime parameter is the timing pulse sent by the handler, used to calculate the 1269 * elapsed duration, and therefore 1270 * the elapsed fraction, of the animation. The return value indicates whether the animation 1271 * should be ended (which happens when the elapsed time of the animation exceeds the 1272 * animation's duration, including the repeatCount). 1273 * 1274 * @param currentTime The current time, as tracked by the static timing handler 1275 * @return true if the animation's duration, including any repetitions due to 1276 * <code>repeatCount</code>, has been exceeded and the animation should be ended. 1277 */ 1278 boolean animationFrame(long currentTime) { 1279 boolean done = false; 1280 switch (mPlayingState) { 1281 case RUNNING: 1282 case SEEKED: 1283 float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f; 1284 if (mDuration == 0 && mRepeatCount != INFINITE) { 1285 // Skip to the end 1286 mCurrentIteration = mRepeatCount; 1287 if (!mReversing) { 1288 mPlayingBackwards = false; 1289 } 1290 } 1291 if (fraction >= 1f) { 1292 if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) { 1293 // Time to repeat 1294 if (mListeners != null) { 1295 int numListeners = mListeners.size(); 1296 for (int i = 0; i < numListeners; ++i) { 1297 mListeners.get(i).onAnimationRepeat(this); 1298 } 1299 } 1300 if (mRepeatMode == REVERSE) { 1301 mPlayingBackwards = !mPlayingBackwards; 1302 } 1303 mCurrentIteration += (int) fraction; 1304 fraction = fraction % 1f; 1305 mStartTime += mDuration; 1306 } else { 1307 done = true; 1308 fraction = Math.min(fraction, 1.0f); 1309 } 1310 } 1311 if (mPlayingBackwards) { 1312 fraction = 1f - fraction; 1313 } 1314 animateValue(fraction); 1315 break; 1316 } 1317 1318 return done; 1319 } 1320 1321 /** 1322 * Processes a frame of the animation, adjusting the start time if needed. 1323 * 1324 * @param frameTime The frame time. 1325 * @return true if the animation has ended. 1326 */ 1327 final boolean doAnimationFrame(long frameTime) { 1328 if (mPlayingState == STOPPED) { 1329 mPlayingState = RUNNING; 1330 if (mSeekFraction < 0) { 1331 mStartTime = frameTime; 1332 } else { 1333 long seekTime = (long) (mDuration * mSeekFraction); 1334 mStartTime = frameTime - seekTime; 1335 mSeekFraction = -1; 1336 } 1337 } 1338 if (mPaused) { 1339 if (mPauseTime < 0) { 1340 mPauseTime = frameTime; 1341 } 1342 return false; 1343 } else if (mResumed) { 1344 mResumed = false; 1345 if (mPauseTime > 0) { 1346 // Offset by the duration that the animation was paused 1347 mStartTime += (frameTime - mPauseTime); 1348 } 1349 } 1350 // The frame time might be before the start time during the first frame of 1351 // an animation. The "current time" must always be on or after the start 1352 // time to avoid animating frames at negative time intervals. In practice, this 1353 // is very rare and only happens when seeking backwards. 1354 final long currentTime = Math.max(frameTime, mStartTime); 1355 return animationFrame(currentTime); 1356 } 1357 1358 /** 1359 * Returns the current animation fraction, which is the elapsed/interpolated fraction used in 1360 * the most recent frame update on the animation. 1361 * 1362 * @return Elapsed/interpolated fraction of the animation. 1363 */ 1364 public float getAnimatedFraction() { 1365 return mCurrentFraction; 1366 } 1367 1368 /** 1369 * This method is called with the elapsed fraction of the animation during every 1370 * animation frame. This function turns the elapsed fraction into an interpolated fraction 1371 * and then into an animated value (from the evaluator. The function is called mostly during 1372 * animation updates, but it is also called when the <code>end()</code> 1373 * function is called, to set the final value on the property. 1374 * 1375 * <p>Overrides of this method must call the superclass to perform the calculation 1376 * of the animated value.</p> 1377 * 1378 * @param fraction The elapsed fraction of the animation. 1379 */ 1380 @CallSuper 1381 void animateValue(float fraction) { 1382 fraction = mInterpolator.getInterpolation(fraction); 1383 mCurrentFraction = fraction; 1384 int numValues = mValues.length; 1385 for (int i = 0; i < numValues; ++i) { 1386 mValues[i].calculateValue(fraction); 1387 } 1388 if (mUpdateListeners != null) { 1389 int numListeners = mUpdateListeners.size(); 1390 for (int i = 0; i < numListeners; ++i) { 1391 mUpdateListeners.get(i).onAnimationUpdate(this); 1392 } 1393 } 1394 } 1395 1396 @Override 1397 public ValueAnimator clone() { 1398 final ValueAnimator anim = (ValueAnimator) super.clone(); 1399 if (mUpdateListeners != null) { 1400 anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>(mUpdateListeners); 1401 } 1402 anim.mSeekFraction = -1; 1403 anim.mPlayingBackwards = false; 1404 anim.mReversing = false; 1405 anim.mCurrentIteration = 0; 1406 anim.mInitialized = false; 1407 anim.mPlayingState = STOPPED; 1408 anim.mStartedDelay = false; 1409 PropertyValuesHolder[] oldValues = mValues; 1410 if (oldValues != null) { 1411 int numValues = oldValues.length; 1412 anim.mValues = new PropertyValuesHolder[numValues]; 1413 anim.mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues); 1414 for (int i = 0; i < numValues; ++i) { 1415 PropertyValuesHolder newValuesHolder = oldValues[i].clone(); 1416 anim.mValues[i] = newValuesHolder; 1417 anim.mValuesMap.put(newValuesHolder.getPropertyName(), newValuesHolder); 1418 } 1419 } 1420 return anim; 1421 } 1422 1423 /** 1424 * Implementors of this interface can add themselves as update listeners 1425 * to an <code>ValueAnimator</code> instance to receive callbacks on every animation 1426 * frame, after the current frame's values have been calculated for that 1427 * <code>ValueAnimator</code>. 1428 */ 1429 public static interface AnimatorUpdateListener { 1430 /** 1431 * <p>Notifies the occurrence of another frame of the animation.</p> 1432 * 1433 * @param animation The animation which was repeated. 1434 */ 1435 void onAnimationUpdate(ValueAnimator animation); 1436 1437 } 1438 1439 /** 1440 * Return the number of animations currently running. 1441 * 1442 * Used by StrictMode internally to annotate violations. 1443 * May be called on arbitrary threads! 1444 * 1445 * @hide 1446 */ 1447 public static int getCurrentAnimationsCount() { 1448 AnimationHandler handler = sAnimationHandler.get(); 1449 return handler != null ? handler.mAnimations.size() : 0; 1450 } 1451 1452 /** 1453 * Clear all animations on this thread, without canceling or ending them. 1454 * This should be used with caution. 1455 * 1456 * @hide 1457 */ 1458 public static void clearAllAnimations() { 1459 AnimationHandler handler = sAnimationHandler.get(); 1460 if (handler != null) { 1461 handler.mAnimations.clear(); 1462 handler.mPendingAnimations.clear(); 1463 handler.mDelayedAnims.clear(); 1464 } 1465 } 1466 1467 private static AnimationHandler getOrCreateAnimationHandler() { 1468 AnimationHandler handler = sAnimationHandler.get(); 1469 if (handler == null) { 1470 handler = new AnimationHandler(); 1471 sAnimationHandler.set(handler); 1472 } 1473 return handler; 1474 } 1475 1476 @Override 1477 public String toString() { 1478 String returnVal = "ValueAnimator@" + Integer.toHexString(hashCode()); 1479 if (mValues != null) { 1480 for (int i = 0; i < mValues.length; ++i) { 1481 returnVal += "\n " + mValues[i].toString(); 1482 } 1483 } 1484 return returnVal; 1485 } 1486 1487 /** 1488 * <p>Whether or not the ValueAnimator is allowed to run asynchronously off of 1489 * the UI thread. This is a hint that informs the ValueAnimator that it is 1490 * OK to run the animation off-thread, however ValueAnimator may decide 1491 * that it must run the animation on the UI thread anyway. For example if there 1492 * is an {@link AnimatorUpdateListener} the animation will run on the UI thread, 1493 * regardless of the value of this hint.</p> 1494 * 1495 * <p>Regardless of whether or not the animation runs asynchronously, all 1496 * listener callbacks will be called on the UI thread.</p> 1497 * 1498 * <p>To be able to use this hint the following must be true:</p> 1499 * <ol> 1500 * <li>{@link #getAnimatedFraction()} is not needed (it will return undefined values).</li> 1501 * <li>The animator is immutable while {@link #isStarted()} is true. Requests 1502 * to change values, duration, delay, etc... may be ignored.</li> 1503 * <li>Lifecycle callback events may be asynchronous. Events such as 1504 * {@link Animator.AnimatorListener#onAnimationEnd(Animator)} or 1505 * {@link Animator.AnimatorListener#onAnimationRepeat(Animator)} may end up delayed 1506 * as they must be posted back to the UI thread, and any actions performed 1507 * by those callbacks (such as starting new animations) will not happen 1508 * in the same frame.</li> 1509 * <li>State change requests ({@link #cancel()}, {@link #end()}, {@link #reverse()}, etc...) 1510 * may be asynchronous. It is guaranteed that all state changes that are 1511 * performed on the UI thread in the same frame will be applied as a single 1512 * atomic update, however that frame may be the current frame, 1513 * the next frame, or some future frame. This will also impact the observed 1514 * state of the Animator. For example, {@link #isStarted()} may still return true 1515 * after a call to {@link #end()}. Using the lifecycle callbacks is preferred over 1516 * queries to {@link #isStarted()}, {@link #isRunning()}, and {@link #isPaused()} 1517 * for this reason.</li> 1518 * </ol> 1519 * @hide 1520 */ 1521 @Override 1522 public void setAllowRunningAsynchronously(boolean mayRunAsync) { 1523 // It is up to subclasses to support this, if they can. 1524 } 1525} 1526