ValueAnimator.java revision 34efbcedac4157b1e92fcd8fd746ba2754b44858
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.content.res.ConfigurationBoundResourceCache; 20import android.os.Debug; 21import android.os.Looper; 22import android.os.Trace; 23import android.util.AndroidRuntimeException; 24import android.view.Choreographer; 25import android.view.animation.AccelerateDecelerateInterpolator; 26import android.view.animation.AnimationUtils; 27import android.view.animation.LinearInterpolator; 28 29import java.util.ArrayList; 30import java.util.HashMap; 31 32/** 33 * This class provides a simple timing engine for running animations 34 * which calculate animated values and set them on target objects. 35 * 36 * <p>There is a single timing pulse that all animations use. It runs in a 37 * custom handler to ensure that property changes happen on the UI thread.</p> 38 * 39 * <p>By default, ValueAnimator uses non-linear time interpolation, via the 40 * {@link AccelerateDecelerateInterpolator} class, which accelerates into and decelerates 41 * out of an animation. This behavior can be changed by calling 42 * {@link ValueAnimator#setInterpolator(TimeInterpolator)}.</p> 43 * 44 * <p>Animators can be created from either code or resource files. Here is an example 45 * of a ValueAnimator resource file:</p> 46 * 47 * {@sample development/samples/ApiDemos/res/anim/animator.xml ValueAnimatorResources} 48 * 49 * <p>It is also possible to use a combination of {@link PropertyValuesHolder} and 50 * {@link Keyframe} resource tags to create a multi-step animation. 51 * Note that you can specify explicit fractional values (from 0 to 1) for 52 * each keyframe to determine when, in the overall duration, the animation should arrive at that 53 * value. Alternatively, you can leave the fractions off and the keyframes will be equally 54 * distributed within the total duration:</p> 55 * 56 * {@sample development/samples/ApiDemos/res/anim/value_animator_pvh_kf.xml 57 * ValueAnimatorKeyframeResources} 58 * 59 * <div class="special reference"> 60 * <h3>Developer Guides</h3> 61 * <p>For more information about animating with {@code ValueAnimator}, read the 62 * <a href="{@docRoot}guide/topics/graphics/prop-animation.html#value-animator">Property 63 * Animation</a> developer guide.</p> 64 * </div> 65 */ 66@SuppressWarnings("unchecked") 67public class ValueAnimator extends Animator { 68 69 /** 70 * Internal constants 71 */ 72 private static float sDurationScale = 1.0f; 73 74 /** 75 * Values used with internal variable mPlayingState to indicate the current state of an 76 * animation. 77 */ 78 static final int STOPPED = 0; // Not yet playing 79 static final int RUNNING = 1; // Playing normally 80 static final int SEEKED = 2; // Seeked to some time value 81 82 /** 83 * Internal variables 84 * NOTE: This object implements the clone() method, making a deep copy of any referenced 85 * objects. As other non-trivial fields are added to this class, make sure to add logic 86 * to clone() to make deep copies of them. 87 */ 88 89 // The first time that the animation's animateFrame() method is called. This time is used to 90 // determine elapsed time (and therefore the elapsed fraction) in subsequent calls 91 // to animateFrame() 92 long mStartTime; 93 94 /** 95 * Set when setCurrentPlayTime() is called. If negative, animation is not currently seeked 96 * to a value. 97 */ 98 float mSeekFraction = -1; 99 100 /** 101 * Set on the next frame after pause() is called, used to calculate a new startTime 102 * or delayStartTime which allows the animator to continue from the point at which 103 * it was paused. If negative, has not yet been set. 104 */ 105 private long mPauseTime; 106 107 /** 108 * Set when an animator is resumed. This triggers logic in the next frame which 109 * actually resumes the animator. 110 */ 111 private boolean mResumed = false; 112 113 114 // The static sAnimationHandler processes the internal timing loop on which all animations 115 // are based 116 /** 117 * @hide 118 */ 119 protected static ThreadLocal<AnimationHandler> sAnimationHandler = 120 new ThreadLocal<AnimationHandler>(); 121 122 // The time interpolator to be used if none is set on the animation 123 private static final TimeInterpolator sDefaultInterpolator = 124 new AccelerateDecelerateInterpolator(); 125 126 /** 127 * Used to indicate whether the animation is currently playing in reverse. This causes the 128 * elapsed fraction to be inverted to calculate the appropriate values. 129 */ 130 private boolean mPlayingBackwards = false; 131 132 /** 133 * Flag to indicate whether this animator is playing in reverse mode, specifically 134 * by being started or interrupted by a call to reverse(). This flag is different than 135 * mPlayingBackwards, which indicates merely whether the current iteration of the 136 * animator is playing in reverse. It is used in corner cases to determine proper end 137 * behavior. 138 */ 139 private boolean mReversing; 140 141 /** 142 * This variable tracks the current iteration that is playing. When mCurrentIteration exceeds the 143 * repeatCount (if repeatCount!=INFINITE), the animation ends 144 */ 145 private int mCurrentIteration = 0; 146 147 /** 148 * Tracks current elapsed/eased fraction, for querying in getAnimatedFraction(). 149 */ 150 private float mCurrentFraction = 0f; 151 152 /** 153 * Tracks whether a startDelay'd animation has begun playing through the startDelay. 154 */ 155 private boolean mStartedDelay = false; 156 157 /** 158 * Tracks the time at which the animation began playing through its startDelay. This is 159 * different from the mStartTime variable, which is used to track when the animation became 160 * active (which is when the startDelay expired and the animation was added to the active 161 * animations list). 162 */ 163 private long mDelayStartTime; 164 165 /** 166 * Flag that represents the current state of the animation. Used to figure out when to start 167 * an animation (if state == STOPPED). Also used to end an animation that 168 * has been cancel()'d or end()'d since the last animation frame. Possible values are 169 * STOPPED, RUNNING, SEEKED. 170 */ 171 int mPlayingState = STOPPED; 172 173 /** 174 * Additional playing state to indicate whether an animator has been start()'d. There is 175 * some lag between a call to start() and the first animation frame. We should still note 176 * that the animation has been started, even if it's first animation frame has not yet 177 * happened, and reflect that state in isRunning(). 178 * Note that delayed animations are different: they are not started until their first 179 * animation frame, which occurs after their delay elapses. 180 */ 181 private boolean mRunning = false; 182 183 /** 184 * Additional playing state to indicate whether an animator has been start()'d, whether or 185 * not there is a nonzero startDelay. 186 */ 187 private boolean mStarted = false; 188 189 /** 190 * Tracks whether we've notified listeners of the onAnimationStart() event. This can be 191 * complex to keep track of since we notify listeners at different times depending on 192 * startDelay and whether start() was called before end(). 193 */ 194 private boolean mStartListenersCalled = false; 195 196 /** 197 * Flag that denotes whether the animation is set up and ready to go. Used to 198 * set up animation that has not yet been started. 199 */ 200 boolean mInitialized = false; 201 202 // 203 // Backing variables 204 // 205 206 // How long the animation should last in ms 207 private long mDuration = (long)(300 * sDurationScale); 208 private long mUnscaledDuration = 300; 209 210 // The amount of time in ms to delay starting the animation after start() is called 211 private long mStartDelay = 0; 212 private long mUnscaledStartDelay = 0; 213 214 // The number of times the animation will repeat. The default is 0, which means the animation 215 // will play only once 216 private int mRepeatCount = 0; 217 218 /** 219 * The type of repetition that will occur when repeatMode is nonzero. RESTART means the 220 * animation will start from the beginning on every new cycle. REVERSE means the animation 221 * will reverse directions on each iteration. 222 */ 223 private int mRepeatMode = RESTART; 224 225 /** 226 * The time interpolator to be used. The elapsed fraction of the animation will be passed 227 * through this interpolator to calculate the interpolated fraction, which is then used to 228 * calculate the animated values. 229 */ 230 private TimeInterpolator mInterpolator = sDefaultInterpolator; 231 232 /** 233 * The set of listeners to be sent events through the life of an animation. 234 */ 235 ArrayList<AnimatorUpdateListener> mUpdateListeners = null; 236 237 /** 238 * The property/value sets being animated. 239 */ 240 PropertyValuesHolder[] mValues; 241 242 /** 243 * A hashmap of the PropertyValuesHolder objects. This map is used to lookup animated values 244 * by property name during calls to getAnimatedValue(String). 245 */ 246 HashMap<String, PropertyValuesHolder> mValuesMap; 247 248 /** 249 * Public constants 250 */ 251 252 /** 253 * When the animation reaches the end and <code>repeatCount</code> is INFINITE 254 * or a positive value, the animation restarts from the beginning. 255 */ 256 public static final int RESTART = 1; 257 /** 258 * When the animation reaches the end and <code>repeatCount</code> is INFINITE 259 * or a positive value, the animation reverses direction on every iteration. 260 */ 261 public static final int REVERSE = 2; 262 /** 263 * This value used used with the {@link #setRepeatCount(int)} property to repeat 264 * the animation indefinitely. 265 */ 266 public static final int INFINITE = -1; 267 268 269 /** 270 * @hide 271 */ 272 public static void setDurationScale(float durationScale) { 273 sDurationScale = durationScale; 274 } 275 276 /** 277 * @hide 278 */ 279 public static float getDurationScale() { 280 return sDurationScale; 281 } 282 283 /** 284 * Creates a new ValueAnimator object. This default constructor is primarily for 285 * use internally; the factory methods which take parameters are more generally 286 * useful. 287 */ 288 public ValueAnimator() { 289 } 290 291 /** 292 * Constructs and returns a ValueAnimator that animates between int values. A single 293 * value implies that that value is the one being animated to. However, this is not typically 294 * useful in a ValueAnimator object because there is no way for the object to determine the 295 * starting value for the animation (unlike ObjectAnimator, which can derive that value 296 * from the target object and property being animated). Therefore, there should typically 297 * be two or more values. 298 * 299 * @param values A set of values that the animation will animate between over time. 300 * @return A ValueAnimator object that is set up to animate between the given values. 301 */ 302 public static ValueAnimator ofInt(int... values) { 303 ValueAnimator anim = new ValueAnimator(); 304 anim.setIntValues(values); 305 return anim; 306 } 307 308 /** 309 * Constructs and returns a ValueAnimator that animates between color values. A single 310 * value implies that that value is the one being animated to. However, this is not typically 311 * useful in a ValueAnimator object because there is no way for the object to determine the 312 * starting value for the animation (unlike ObjectAnimator, which can derive that value 313 * from the target object and property being animated). Therefore, there should typically 314 * be two or more values. 315 * 316 * @param values A set of values that the animation will animate between over time. 317 * @return A ValueAnimator object that is set up to animate between the given values. 318 */ 319 public static ValueAnimator ofArgb(int... values) { 320 ValueAnimator anim = new ValueAnimator(); 321 anim.setIntValues(values); 322 anim.setEvaluator(ArgbEvaluator.getInstance()); 323 return anim; 324 } 325 326 /** 327 * Constructs and returns a ValueAnimator that animates between float values. A single 328 * value implies that that value is the one being animated to. However, this is not typically 329 * useful in a ValueAnimator object because there is no way for the object to determine the 330 * starting value for the animation (unlike ObjectAnimator, which can derive that value 331 * from the target object and property being animated). Therefore, there should typically 332 * be two or more values. 333 * 334 * @param values A set of values that the animation will animate between over time. 335 * @return A ValueAnimator object that is set up to animate between the given values. 336 */ 337 public static ValueAnimator ofFloat(float... values) { 338 ValueAnimator anim = new ValueAnimator(); 339 anim.setFloatValues(values); 340 return anim; 341 } 342 343 /** 344 * Constructs and returns a ValueAnimator that animates between the values 345 * specified in the PropertyValuesHolder objects. 346 * 347 * @param values A set of PropertyValuesHolder objects whose values will be animated 348 * between over time. 349 * @return A ValueAnimator object that is set up to animate between the given values. 350 */ 351 public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values) { 352 ValueAnimator anim = new ValueAnimator(); 353 anim.setValues(values); 354 return anim; 355 } 356 /** 357 * Constructs and returns a ValueAnimator that animates between Object values. A single 358 * value implies that that value is the one being animated to. However, this is not typically 359 * useful in a ValueAnimator object because there is no way for the object to determine the 360 * starting value for the animation (unlike ObjectAnimator, which can derive that value 361 * from the target object and property being animated). Therefore, there should typically 362 * be two or more values. 363 * 364 * <p>Since ValueAnimator does not know how to animate between arbitrary Objects, this 365 * factory method also takes a TypeEvaluator object that the ValueAnimator will use 366 * to perform that interpolation. 367 * 368 * @param evaluator A TypeEvaluator that will be called on each animation frame to 369 * provide the ncessry interpolation between the Object values to derive the animated 370 * value. 371 * @param values A set of values that the animation will animate between over time. 372 * @return A ValueAnimator object that is set up to animate between the given values. 373 */ 374 public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) { 375 ValueAnimator anim = new ValueAnimator(); 376 anim.setObjectValues(values); 377 anim.setEvaluator(evaluator); 378 return anim; 379 } 380 381 /** 382 * Sets int values that will be animated between. A single 383 * value implies that that value is the one being animated to. However, this is not typically 384 * useful in a ValueAnimator object because there is no way for the object to determine the 385 * starting value for the animation (unlike ObjectAnimator, which can derive that value 386 * from the target object and property being animated). Therefore, there should typically 387 * be two or more values. 388 * 389 * <p>If there are already multiple sets of values defined for this ValueAnimator via more 390 * than one PropertyValuesHolder object, this method will set the values for the first 391 * of those objects.</p> 392 * 393 * @param values A set of values that the animation will animate between over time. 394 */ 395 public void setIntValues(int... values) { 396 if (values == null || values.length == 0) { 397 return; 398 } 399 if (mValues == null || mValues.length == 0) { 400 setValues(PropertyValuesHolder.ofInt("", values)); 401 } else { 402 PropertyValuesHolder valuesHolder = mValues[0]; 403 valuesHolder.setIntValues(values); 404 } 405 // New property/values/target should cause re-initialization prior to starting 406 mInitialized = false; 407 } 408 409 /** 410 * Sets float values that will be animated between. A single 411 * value implies that that value is the one being animated to. However, this is not typically 412 * useful in a ValueAnimator object because there is no way for the object to determine the 413 * starting value for the animation (unlike ObjectAnimator, which can derive that value 414 * from the target object and property being animated). Therefore, there should typically 415 * be two or more values. 416 * 417 * <p>If there are already multiple sets of values defined for this ValueAnimator via more 418 * than one PropertyValuesHolder object, this method will set the values for the first 419 * of those objects.</p> 420 * 421 * @param values A set of values that the animation will animate between over time. 422 */ 423 public void setFloatValues(float... values) { 424 if (values == null || values.length == 0) { 425 return; 426 } 427 if (mValues == null || mValues.length == 0) { 428 setValues(PropertyValuesHolder.ofFloat("", values)); 429 } else { 430 PropertyValuesHolder valuesHolder = mValues[0]; 431 valuesHolder.setFloatValues(values); 432 } 433 // New property/values/target should cause re-initialization prior to starting 434 mInitialized = false; 435 } 436 437 /** 438 * Sets the values to animate between for this animation. A single 439 * value implies that that value is the one being animated to. However, this is not typically 440 * useful in a ValueAnimator object because there is no way for the object to determine the 441 * starting value for the animation (unlike ObjectAnimator, which can derive that value 442 * from the target object and property being animated). Therefore, there should typically 443 * be two or more values. 444 * 445 * <p>If there are already multiple sets of values defined for this ValueAnimator via more 446 * than one PropertyValuesHolder object, this method will set the values for the first 447 * of those objects.</p> 448 * 449 * <p>There should be a TypeEvaluator set on the ValueAnimator that knows how to interpolate 450 * between these value objects. ValueAnimator only knows how to interpolate between the 451 * primitive types specified in the other setValues() methods.</p> 452 * 453 * @param values The set of values to animate between. 454 */ 455 public void setObjectValues(Object... values) { 456 if (values == null || values.length == 0) { 457 return; 458 } 459 if (mValues == null || mValues.length == 0) { 460 setValues(PropertyValuesHolder.ofObject("", null, values)); 461 } else { 462 PropertyValuesHolder valuesHolder = mValues[0]; 463 valuesHolder.setObjectValues(values); 464 } 465 // New property/values/target should cause re-initialization prior to starting 466 mInitialized = false; 467 } 468 469 /** 470 * Sets the values, per property, being animated between. This function is called internally 471 * by the constructors of ValueAnimator that take a list of values. But a ValueAnimator can 472 * be constructed without values and this method can be called to set the values manually 473 * instead. 474 * 475 * @param values The set of values, per property, being animated between. 476 */ 477 public void setValues(PropertyValuesHolder... values) { 478 int numValues = values.length; 479 mValues = values; 480 mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues); 481 for (int i = 0; i < numValues; ++i) { 482 PropertyValuesHolder valuesHolder = values[i]; 483 mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder); 484 } 485 // New property/values/target should cause re-initialization prior to starting 486 mInitialized = false; 487 } 488 489 /** 490 * Returns the values that this ValueAnimator animates between. These values are stored in 491 * PropertyValuesHolder objects, even if the ValueAnimator was created with a simple list 492 * of value objects instead. 493 * 494 * @return PropertyValuesHolder[] An array of PropertyValuesHolder objects which hold the 495 * values, per property, that define the animation. 496 */ 497 public PropertyValuesHolder[] getValues() { 498 return mValues; 499 } 500 501 /** 502 * This function is called immediately before processing the first animation 503 * frame of an animation. If there is a nonzero <code>startDelay</code>, the 504 * function is called after that delay ends. 505 * It takes care of the final initialization steps for the 506 * animation. 507 * 508 * <p>Overrides of this method should call the superclass method to ensure 509 * that internal mechanisms for the animation are set up correctly.</p> 510 */ 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 void animateValue(float fraction) { 1381 fraction = mInterpolator.getInterpolation(fraction); 1382 mCurrentFraction = fraction; 1383 int numValues = mValues.length; 1384 for (int i = 0; i < numValues; ++i) { 1385 mValues[i].calculateValue(fraction); 1386 } 1387 if (mUpdateListeners != null) { 1388 int numListeners = mUpdateListeners.size(); 1389 for (int i = 0; i < numListeners; ++i) { 1390 mUpdateListeners.get(i).onAnimationUpdate(this); 1391 } 1392 } 1393 } 1394 1395 @Override 1396 public ValueAnimator clone() { 1397 final ValueAnimator anim = (ValueAnimator) super.clone(); 1398 if (mUpdateListeners != null) { 1399 anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>(mUpdateListeners); 1400 } 1401 anim.mSeekFraction = -1; 1402 anim.mPlayingBackwards = false; 1403 anim.mReversing = false; 1404 anim.mCurrentIteration = 0; 1405 anim.mInitialized = false; 1406 anim.mPlayingState = STOPPED; 1407 anim.mStartedDelay = false; 1408 PropertyValuesHolder[] oldValues = mValues; 1409 if (oldValues != null) { 1410 int numValues = oldValues.length; 1411 anim.mValues = new PropertyValuesHolder[numValues]; 1412 anim.mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues); 1413 for (int i = 0; i < numValues; ++i) { 1414 PropertyValuesHolder newValuesHolder = oldValues[i].clone(); 1415 anim.mValues[i] = newValuesHolder; 1416 anim.mValuesMap.put(newValuesHolder.getPropertyName(), newValuesHolder); 1417 } 1418 } 1419 return anim; 1420 } 1421 1422 /** 1423 * Implementors of this interface can add themselves as update listeners 1424 * to an <code>ValueAnimator</code> instance to receive callbacks on every animation 1425 * frame, after the current frame's values have been calculated for that 1426 * <code>ValueAnimator</code>. 1427 */ 1428 public static interface AnimatorUpdateListener { 1429 /** 1430 * <p>Notifies the occurrence of another frame of the animation.</p> 1431 * 1432 * @param animation The animation which was repeated. 1433 */ 1434 void onAnimationUpdate(ValueAnimator animation); 1435 1436 } 1437 1438 /** 1439 * Return the number of animations currently running. 1440 * 1441 * Used by StrictMode internally to annotate violations. 1442 * May be called on arbitrary threads! 1443 * 1444 * @hide 1445 */ 1446 public static int getCurrentAnimationsCount() { 1447 AnimationHandler handler = sAnimationHandler.get(); 1448 return handler != null ? handler.mAnimations.size() : 0; 1449 } 1450 1451 /** 1452 * Clear all animations on this thread, without canceling or ending them. 1453 * This should be used with caution. 1454 * 1455 * @hide 1456 */ 1457 public static void clearAllAnimations() { 1458 AnimationHandler handler = sAnimationHandler.get(); 1459 if (handler != null) { 1460 handler.mAnimations.clear(); 1461 handler.mPendingAnimations.clear(); 1462 handler.mDelayedAnims.clear(); 1463 } 1464 } 1465 1466 private static AnimationHandler getOrCreateAnimationHandler() { 1467 AnimationHandler handler = sAnimationHandler.get(); 1468 if (handler == null) { 1469 handler = new AnimationHandler(); 1470 sAnimationHandler.set(handler); 1471 } 1472 return handler; 1473 } 1474 1475 @Override 1476 public String toString() { 1477 String returnVal = "ValueAnimator@" + Integer.toHexString(hashCode()); 1478 if (mValues != null) { 1479 for (int i = 0; i < mValues.length; ++i) { 1480 returnVal += "\n " + mValues[i].toString(); 1481 } 1482 } 1483 return returnVal; 1484 } 1485 1486 /** 1487 * <p>Whether or not the ValueAnimator is allowed to run asynchronously off of 1488 * the UI thread. This is a hint that informs the ValueAnimator that it is 1489 * OK to run the animation off-thread, however ValueAnimator may decide 1490 * that it must run the animation on the UI thread anyway. For example if there 1491 * is an {@link AnimatorUpdateListener} the animation will run on the UI thread, 1492 * regardless of the value of this hint.</p> 1493 * 1494 * <p>Regardless of whether or not the animation runs asynchronously, all 1495 * listener callbacks will be called on the UI thread.</p> 1496 * 1497 * <p>To be able to use this hint the following must be true:</p> 1498 * <ol> 1499 * <li>{@link #getAnimatedFraction()} is not needed (it will return undefined values).</li> 1500 * <li>The animator is immutable while {@link #isStarted()} is true. Requests 1501 * to change values, duration, delay, etc... may be ignored.</li> 1502 * <li>Lifecycle callback events may be asynchronous. Events such as 1503 * {@link Animator.AnimatorListener#onAnimationEnd(Animator)} or 1504 * {@link Animator.AnimatorListener#onAnimationRepeat(Animator)} may end up delayed 1505 * as they must be posted back to the UI thread, and any actions performed 1506 * by those callbacks (such as starting new animations) will not happen 1507 * in the same frame.</li> 1508 * <li>State change requests ({@link #cancel()}, {@link #end()}, {@link #reverse()}, etc...) 1509 * may be asynchronous. It is guaranteed that all state changes that are 1510 * performed on the UI thread in the same frame will be applied as a single 1511 * atomic update, however that frame may be the current frame, 1512 * the next frame, or some future frame. This will also impact the observed 1513 * state of the Animator. For example, {@link #isStarted()} may still return true 1514 * after a call to {@link #end()}. Using the lifecycle callbacks is preferred over 1515 * queries to {@link #isStarted()}, {@link #isRunning()}, and {@link #isPaused()} 1516 * for this reason.</li> 1517 * </ol> 1518 * @hide 1519 */ 1520 @Override 1521 public void setAllowRunningAsynchronously(boolean mayRunAsync) { 1522 // It is up to subclasses to support this, if they can. 1523 } 1524} 1525