ValueAnimator.java revision 3aef8e1d1b2f0b87d470bcccf37ba4ebb6560c45
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.os.Handler; 20import android.os.Looper; 21import android.os.Message; 22import android.util.AndroidRuntimeException; 23import android.view.animation.AccelerateDecelerateInterpolator; 24import android.view.animation.AnimationUtils; 25import android.view.animation.LinearInterpolator; 26 27import java.util.ArrayList; 28import java.util.HashMap; 29 30/** 31 * This class provides a simple timing engine for running animations 32 * which calculate animated values and set them on target objects. 33 * 34 * <p>There is a single timing pulse that all animations use. It runs in a 35 * custom handler to ensure that property changes happen on the UI thread.</p> 36 * 37 * <p>By default, ValueAnimator uses non-linear time interpolation, via the 38 * {@link AccelerateDecelerateInterpolator} class, which accelerates into and decelerates 39 * out of an animation. This behavior can be changed by calling 40 * {@link ValueAnimator#setInterpolator(TimeInterpolator)}.</p> 41 * 42 * <div class="special reference"> 43 * <h3>Developer Guides</h3> 44 * <p>For more information about animating with {@code ValueAnimator}, read the 45 * <a href="{@docRoot}guide/topics/graphics/prop-animation.html#value-animator">Property 46 * Animation</a> developer guide.</p> 47 * </div> 48 */ 49public class ValueAnimator extends Animator { 50 51 /** 52 * Internal constants 53 */ 54 55 /* 56 * The default amount of time in ms between animation frames 57 */ 58 private static final long DEFAULT_FRAME_DELAY = 10; 59 60 /** 61 * Messages sent to timing handler: START is sent when an animation first begins, FRAME is sent 62 * by the handler to itself to process the next animation frame 63 */ 64 static final int ANIMATION_START = 0; 65 static final int ANIMATION_FRAME = 1; 66 67 /** 68 * Values used with internal variable mPlayingState to indicate the current state of an 69 * animation. 70 */ 71 static final int STOPPED = 0; // Not yet playing 72 static final int RUNNING = 1; // Playing normally 73 static final int SEEKED = 2; // Seeked to some time value 74 75 /** 76 * Internal variables 77 * NOTE: This object implements the clone() method, making a deep copy of any referenced 78 * objects. As other non-trivial fields are added to this class, make sure to add logic 79 * to clone() to make deep copies of them. 80 */ 81 82 // The first time that the animation's animateFrame() method is called. This time is used to 83 // determine elapsed time (and therefore the elapsed fraction) in subsequent calls 84 // to animateFrame() 85 long mStartTime; 86 87 /** 88 * Set when setCurrentPlayTime() is called. If negative, animation is not currently seeked 89 * to a value. 90 */ 91 long mSeekTime = -1; 92 93 // TODO: We access the following ThreadLocal variables often, some of them on every update. 94 // If ThreadLocal access is significantly expensive, we may want to put all of these 95 // fields into a structure sot hat we just access ThreadLocal once to get the reference 96 // to that structure, then access the structure directly for each field. 97 98 // The static sAnimationHandler processes the internal timing loop on which all animations 99 // are based 100 private static ThreadLocal<AnimationHandler> sAnimationHandler = 101 new ThreadLocal<AnimationHandler>(); 102 103 // The per-thread list of all active animations 104 private static final ThreadLocal<ArrayList<ValueAnimator>> sAnimations = 105 new ThreadLocal<ArrayList<ValueAnimator>>() { 106 @Override 107 protected ArrayList<ValueAnimator> initialValue() { 108 return new ArrayList<ValueAnimator>(); 109 } 110 }; 111 112 // The per-thread set of animations to be started on the next animation frame 113 private static final ThreadLocal<ArrayList<ValueAnimator>> sPendingAnimations = 114 new ThreadLocal<ArrayList<ValueAnimator>>() { 115 @Override 116 protected ArrayList<ValueAnimator> initialValue() { 117 return new ArrayList<ValueAnimator>(); 118 } 119 }; 120 121 /** 122 * Internal per-thread collections used to avoid set collisions as animations start and end 123 * while being processed. 124 */ 125 private static final ThreadLocal<ArrayList<ValueAnimator>> sDelayedAnims = 126 new ThreadLocal<ArrayList<ValueAnimator>>() { 127 @Override 128 protected ArrayList<ValueAnimator> initialValue() { 129 return new ArrayList<ValueAnimator>(); 130 } 131 }; 132 133 private static final ThreadLocal<ArrayList<ValueAnimator>> sEndingAnims = 134 new ThreadLocal<ArrayList<ValueAnimator>>() { 135 @Override 136 protected ArrayList<ValueAnimator> initialValue() { 137 return new ArrayList<ValueAnimator>(); 138 } 139 }; 140 141 private static final ThreadLocal<ArrayList<ValueAnimator>> sReadyAnims = 142 new ThreadLocal<ArrayList<ValueAnimator>>() { 143 @Override 144 protected ArrayList<ValueAnimator> initialValue() { 145 return new ArrayList<ValueAnimator>(); 146 } 147 }; 148 149 // The time interpolator to be used if none is set on the animation 150 private static final TimeInterpolator sDefaultInterpolator = 151 new AccelerateDecelerateInterpolator(); 152 153 // type evaluators for the primitive types handled by this implementation 154 private static final TypeEvaluator sIntEvaluator = new IntEvaluator(); 155 private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator(); 156 157 /** 158 * Used to indicate whether the animation is currently playing in reverse. This causes the 159 * elapsed fraction to be inverted to calculate the appropriate values. 160 */ 161 private boolean mPlayingBackwards = false; 162 163 /** 164 * This variable tracks the current iteration that is playing. When mCurrentIteration exceeds the 165 * repeatCount (if repeatCount!=INFINITE), the animation ends 166 */ 167 private int mCurrentIteration = 0; 168 169 /** 170 * Tracks current elapsed/eased fraction, for querying in getAnimatedFraction(). 171 */ 172 private float mCurrentFraction = 0f; 173 174 /** 175 * Tracks whether a startDelay'd animation has begun playing through the startDelay. 176 */ 177 private boolean mStartedDelay = false; 178 179 /** 180 * Tracks the time at which the animation began playing through its startDelay. This is 181 * different from the mStartTime variable, which is used to track when the animation became 182 * active (which is when the startDelay expired and the animation was added to the active 183 * animations list). 184 */ 185 private long mDelayStartTime; 186 187 /** 188 * Flag that represents the current state of the animation. Used to figure out when to start 189 * an animation (if state == STOPPED). Also used to end an animation that 190 * has been cancel()'d or end()'d since the last animation frame. Possible values are 191 * STOPPED, RUNNING, SEEKED. 192 */ 193 int mPlayingState = STOPPED; 194 195 /** 196 * Additional playing state to indicate whether an animator has been start()'d. There is 197 * some lag between a call to start() and the first animation frame. We should still note 198 * that the animation has been started, even if it's first animation frame has not yet 199 * happened, and reflect that state in isRunning(). 200 * Note that delayed animations are different: they are not started until their first 201 * animation frame, which occurs after their delay elapses. 202 */ 203 private boolean mRunning = false; 204 205 /** 206 * Additional playing state to indicate whether an animator has been start()'d, whether or 207 * not there is a nonzero startDelay. 208 */ 209 private boolean mStarted = false; 210 211 /** 212 * Flag that denotes whether the animation is set up and ready to go. Used to 213 * set up animation that has not yet been started. 214 */ 215 boolean mInitialized = false; 216 217 // 218 // Backing variables 219 // 220 221 // How long the animation should last in ms 222 private long mDuration = 300; 223 224 // The amount of time in ms to delay starting the animation after start() is called 225 private long mStartDelay = 0; 226 227 // The number of milliseconds between animation frames 228 private static long sFrameDelay = DEFAULT_FRAME_DELAY; 229 230 // The number of times the animation will repeat. The default is 0, which means the animation 231 // will play only once 232 private int mRepeatCount = 0; 233 234 /** 235 * The type of repetition that will occur when repeatMode is nonzero. RESTART means the 236 * animation will start from the beginning on every new cycle. REVERSE means the animation 237 * will reverse directions on each iteration. 238 */ 239 private int mRepeatMode = RESTART; 240 241 /** 242 * The time interpolator to be used. The elapsed fraction of the animation will be passed 243 * through this interpolator to calculate the interpolated fraction, which is then used to 244 * calculate the animated values. 245 */ 246 private TimeInterpolator mInterpolator = sDefaultInterpolator; 247 248 /** 249 * The set of listeners to be sent events through the life of an animation. 250 */ 251 private ArrayList<AnimatorUpdateListener> mUpdateListeners = null; 252 253 /** 254 * The property/value sets being animated. 255 */ 256 PropertyValuesHolder[] mValues; 257 258 /** 259 * A hashmap of the PropertyValuesHolder objects. This map is used to lookup animated values 260 * by property name during calls to getAnimatedValue(String). 261 */ 262 HashMap<String, PropertyValuesHolder> mValuesMap; 263 264 /** 265 * Public constants 266 */ 267 268 /** 269 * When the animation reaches the end and <code>repeatCount</code> is INFINITE 270 * or a positive value, the animation restarts from the beginning. 271 */ 272 public static final int RESTART = 1; 273 /** 274 * When the animation reaches the end and <code>repeatCount</code> is INFINITE 275 * or a positive value, the animation reverses direction on every iteration. 276 */ 277 public static final int REVERSE = 2; 278 /** 279 * This value used used with the {@link #setRepeatCount(int)} property to repeat 280 * the animation indefinitely. 281 */ 282 public static final int INFINITE = -1; 283 284 /** 285 * Creates a new ValueAnimator object. This default constructor is primarily for 286 * use internally; the factory methods which take parameters are more generally 287 * useful. 288 */ 289 public ValueAnimator() { 290 } 291 292 /** 293 * Constructs and returns a ValueAnimator that animates between int values. A single 294 * value implies that that value is the one being animated to. However, this is not typically 295 * useful in a ValueAnimator object because there is no way for the object to determine the 296 * starting value for the animation (unlike ObjectAnimator, which can derive that value 297 * from the target object and property being animated). Therefore, there should typically 298 * be two or more values. 299 * 300 * @param values A set of values that the animation will animate between over time. 301 * @return A ValueAnimator object that is set up to animate between the given values. 302 */ 303 public static ValueAnimator ofInt(int... values) { 304 ValueAnimator anim = new ValueAnimator(); 305 anim.setIntValues(values); 306 return anim; 307 } 308 309 /** 310 * Constructs and returns a ValueAnimator that animates between float values. A single 311 * value implies that that value is the one being animated to. However, this is not typically 312 * useful in a ValueAnimator object because there is no way for the object to determine the 313 * starting value for the animation (unlike ObjectAnimator, which can derive that value 314 * from the target object and property being animated). Therefore, there should typically 315 * be two or more values. 316 * 317 * @param values A set of values that the animation will animate between over time. 318 * @return A ValueAnimator object that is set up to animate between the given values. 319 */ 320 public static ValueAnimator ofFloat(float... values) { 321 ValueAnimator anim = new ValueAnimator(); 322 anim.setFloatValues(values); 323 return anim; 324 } 325 326 /** 327 * Constructs and returns a ValueAnimator that animates between the values 328 * specified in the PropertyValuesHolder objects. 329 * 330 * @param values A set of PropertyValuesHolder objects whose values will be animated 331 * between over time. 332 * @return A ValueAnimator object that is set up to animate between the given values. 333 */ 334 public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values) { 335 ValueAnimator anim = new ValueAnimator(); 336 anim.setValues(values); 337 return anim; 338 } 339 /** 340 * Constructs and returns a ValueAnimator that animates between Object values. A single 341 * value implies that that value is the one being animated to. However, this is not typically 342 * useful in a ValueAnimator object because there is no way for the object to determine the 343 * starting value for the animation (unlike ObjectAnimator, which can derive that value 344 * from the target object and property being animated). Therefore, there should typically 345 * be two or more values. 346 * 347 * <p>Since ValueAnimator does not know how to animate between arbitrary Objects, this 348 * factory method also takes a TypeEvaluator object that the ValueAnimator will use 349 * to perform that interpolation. 350 * 351 * @param evaluator A TypeEvaluator that will be called on each animation frame to 352 * provide the ncessry interpolation between the Object values to derive the animated 353 * value. 354 * @param values A set of values that the animation will animate between over time. 355 * @return A ValueAnimator object that is set up to animate between the given values. 356 */ 357 public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) { 358 ValueAnimator anim = new ValueAnimator(); 359 anim.setObjectValues(values); 360 anim.setEvaluator(evaluator); 361 return anim; 362 } 363 364 /** 365 * Sets int values that will be animated between. A single 366 * value implies that that value is the one being animated to. However, this is not typically 367 * useful in a ValueAnimator object because there is no way for the object to determine the 368 * starting value for the animation (unlike ObjectAnimator, which can derive that value 369 * from the target object and property being animated). Therefore, there should typically 370 * be two or more values. 371 * 372 * <p>If there are already multiple sets of values defined for this ValueAnimator via more 373 * than one PropertyValuesHolder object, this method will set the values for the first 374 * of those objects.</p> 375 * 376 * @param values A set of values that the animation will animate between over time. 377 */ 378 public void setIntValues(int... values) { 379 if (values == null || values.length == 0) { 380 return; 381 } 382 if (mValues == null || mValues.length == 0) { 383 setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofInt("", values)}); 384 } else { 385 PropertyValuesHolder valuesHolder = mValues[0]; 386 valuesHolder.setIntValues(values); 387 } 388 // New property/values/target should cause re-initialization prior to starting 389 mInitialized = false; 390 } 391 392 /** 393 * Sets float values that will be animated between. A single 394 * value implies that that value is the one being animated to. However, this is not typically 395 * useful in a ValueAnimator object because there is no way for the object to determine the 396 * starting value for the animation (unlike ObjectAnimator, which can derive that value 397 * from the target object and property being animated). Therefore, there should typically 398 * be two or more values. 399 * 400 * <p>If there are already multiple sets of values defined for this ValueAnimator via more 401 * than one PropertyValuesHolder object, this method will set the values for the first 402 * of those objects.</p> 403 * 404 * @param values A set of values that the animation will animate between over time. 405 */ 406 public void setFloatValues(float... values) { 407 if (values == null || values.length == 0) { 408 return; 409 } 410 if (mValues == null || mValues.length == 0) { 411 setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofFloat("", values)}); 412 } else { 413 PropertyValuesHolder valuesHolder = mValues[0]; 414 valuesHolder.setFloatValues(values); 415 } 416 // New property/values/target should cause re-initialization prior to starting 417 mInitialized = false; 418 } 419 420 /** 421 * Sets the values to animate between for this animation. A single 422 * value implies that that value is the one being animated to. However, this is not typically 423 * useful in a ValueAnimator object because there is no way for the object to determine the 424 * starting value for the animation (unlike ObjectAnimator, which can derive that value 425 * from the target object and property being animated). Therefore, there should typically 426 * be two or more values. 427 * 428 * <p>If there are already multiple sets of values defined for this ValueAnimator via more 429 * than one PropertyValuesHolder object, this method will set the values for the first 430 * of those objects.</p> 431 * 432 * <p>There should be a TypeEvaluator set on the ValueAnimator that knows how to interpolate 433 * between these value objects. ValueAnimator only knows how to interpolate between the 434 * primitive types specified in the other setValues() methods.</p> 435 * 436 * @param values The set of values to animate between. 437 */ 438 public void setObjectValues(Object... values) { 439 if (values == null || values.length == 0) { 440 return; 441 } 442 if (mValues == null || mValues.length == 0) { 443 setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofObject("", 444 (TypeEvaluator)null, values)}); 445 } else { 446 PropertyValuesHolder valuesHolder = mValues[0]; 447 valuesHolder.setObjectValues(values); 448 } 449 // New property/values/target should cause re-initialization prior to starting 450 mInitialized = false; 451 } 452 453 /** 454 * Sets the values, per property, being animated between. This function is called internally 455 * by the constructors of ValueAnimator that take a list of values. But an ValueAnimator can 456 * be constructed without values and this method can be called to set the values manually 457 * instead. 458 * 459 * @param values The set of values, per property, being animated between. 460 */ 461 public void setValues(PropertyValuesHolder... values) { 462 int numValues = values.length; 463 mValues = values; 464 mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues); 465 for (int i = 0; i < numValues; ++i) { 466 PropertyValuesHolder valuesHolder = (PropertyValuesHolder) values[i]; 467 mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder); 468 } 469 // New property/values/target should cause re-initialization prior to starting 470 mInitialized = false; 471 } 472 473 /** 474 * Returns the values that this ValueAnimator animates between. These values are stored in 475 * PropertyValuesHolder objects, even if the ValueAnimator was created with a simple list 476 * of value objects instead. 477 * 478 * @return PropertyValuesHolder[] An array of PropertyValuesHolder objects which hold the 479 * values, per property, that define the animation. 480 */ 481 public PropertyValuesHolder[] getValues() { 482 return mValues; 483 } 484 485 /** 486 * This function is called immediately before processing the first animation 487 * frame of an animation. If there is a nonzero <code>startDelay</code>, the 488 * function is called after that delay ends. 489 * It takes care of the final initialization steps for the 490 * animation. 491 * 492 * <p>Overrides of this method should call the superclass method to ensure 493 * that internal mechanisms for the animation are set up correctly.</p> 494 */ 495 void initAnimation() { 496 if (!mInitialized) { 497 int numValues = mValues.length; 498 for (int i = 0; i < numValues; ++i) { 499 mValues[i].init(); 500 } 501 mInitialized = true; 502 } 503 } 504 505 506 /** 507 * Sets the length of the animation. The default duration is 300 milliseconds. 508 * 509 * @param duration The length of the animation, in milliseconds. This value cannot 510 * be negative. 511 * @return ValueAnimator The object called with setDuration(). This return 512 * value makes it easier to compose statements together that construct and then set the 513 * duration, as in <code>ValueAnimator.ofInt(0, 10).setDuration(500).start()</code>. 514 */ 515 public ValueAnimator setDuration(long duration) { 516 if (duration < 0) { 517 throw new IllegalArgumentException("Animators cannot have negative duration: " + 518 duration); 519 } 520 mDuration = duration; 521 return this; 522 } 523 524 /** 525 * Gets the length of the animation. The default duration is 300 milliseconds. 526 * 527 * @return The length of the animation, in milliseconds. 528 */ 529 public long getDuration() { 530 return mDuration; 531 } 532 533 /** 534 * Sets the position of the animation to the specified point in time. This time should 535 * be between 0 and the total duration of the animation, including any repetition. If 536 * the animation has not yet been started, then it will not advance forward after it is 537 * set to this time; it will simply set the time to this value and perform any appropriate 538 * actions based on that time. If the animation is already running, then setCurrentPlayTime() 539 * will set the current playing time to this value and continue playing from that point. 540 * 541 * @param playTime The time, in milliseconds, to which the animation is advanced or rewound. 542 */ 543 public void setCurrentPlayTime(long playTime) { 544 initAnimation(); 545 long currentTime = AnimationUtils.currentAnimationTimeMillis(); 546 if (mPlayingState != RUNNING) { 547 mSeekTime = playTime; 548 mPlayingState = SEEKED; 549 } 550 mStartTime = currentTime - playTime; 551 animationFrame(currentTime); 552 } 553 554 /** 555 * Gets the current position of the animation in time, which is equal to the current 556 * time minus the time that the animation started. An animation that is not yet started will 557 * return a value of zero. 558 * 559 * @return The current position in time of the animation. 560 */ 561 public long getCurrentPlayTime() { 562 if (!mInitialized || mPlayingState == STOPPED) { 563 return 0; 564 } 565 return AnimationUtils.currentAnimationTimeMillis() - mStartTime; 566 } 567 568 /** 569 * This custom, static handler handles the timing pulse that is shared by 570 * all active animations. This approach ensures that the setting of animation 571 * values will happen on the UI thread and that all animations will share 572 * the same times for calculating their values, which makes synchronizing 573 * animations possible. 574 * 575 */ 576 private static class AnimationHandler extends Handler { 577 /** 578 * There are only two messages that we care about: ANIMATION_START and 579 * ANIMATION_FRAME. The START message is sent when an animation's start() 580 * method is called. It cannot start synchronously when start() is called 581 * because the call may be on the wrong thread, and it would also not be 582 * synchronized with other animations because it would not start on a common 583 * timing pulse. So each animation sends a START message to the handler, which 584 * causes the handler to place the animation on the active animations queue and 585 * start processing frames for that animation. 586 * The FRAME message is the one that is sent over and over while there are any 587 * active animations to process. 588 */ 589 @Override 590 public void handleMessage(Message msg) { 591 boolean callAgain = true; 592 ArrayList<ValueAnimator> animations = sAnimations.get(); 593 ArrayList<ValueAnimator> delayedAnims = sDelayedAnims.get(); 594 switch (msg.what) { 595 // TODO: should we avoid sending frame message when starting if we 596 // were already running? 597 case ANIMATION_START: 598 ArrayList<ValueAnimator> pendingAnimations = sPendingAnimations.get(); 599 if (animations.size() > 0 || delayedAnims.size() > 0) { 600 callAgain = false; 601 } 602 // pendingAnims holds any animations that have requested to be started 603 // We're going to clear sPendingAnimations, but starting animation may 604 // cause more to be added to the pending list (for example, if one animation 605 // starting triggers another starting). So we loop until sPendingAnimations 606 // is empty. 607 while (pendingAnimations.size() > 0) { 608 ArrayList<ValueAnimator> pendingCopy = 609 (ArrayList<ValueAnimator>) pendingAnimations.clone(); 610 pendingAnimations.clear(); 611 int count = pendingCopy.size(); 612 for (int i = 0; i < count; ++i) { 613 ValueAnimator anim = pendingCopy.get(i); 614 // If the animation has a startDelay, place it on the delayed list 615 if (anim.mStartDelay == 0) { 616 anim.startAnimation(); 617 } else { 618 delayedAnims.add(anim); 619 } 620 } 621 } 622 // fall through to process first frame of new animations 623 case ANIMATION_FRAME: 624 // currentTime holds the common time for all animations processed 625 // during this frame 626 long currentTime = AnimationUtils.currentAnimationTimeMillis(); 627 ArrayList<ValueAnimator> readyAnims = sReadyAnims.get(); 628 ArrayList<ValueAnimator> endingAnims = sEndingAnims.get(); 629 630 // First, process animations currently sitting on the delayed queue, adding 631 // them to the active animations if they are ready 632 int numDelayedAnims = delayedAnims.size(); 633 for (int i = 0; i < numDelayedAnims; ++i) { 634 ValueAnimator anim = delayedAnims.get(i); 635 if (anim.delayedAnimationFrame(currentTime)) { 636 readyAnims.add(anim); 637 } 638 } 639 int numReadyAnims = readyAnims.size(); 640 if (numReadyAnims > 0) { 641 for (int i = 0; i < numReadyAnims; ++i) { 642 ValueAnimator anim = readyAnims.get(i); 643 anim.startAnimation(); 644 anim.mRunning = true; 645 delayedAnims.remove(anim); 646 } 647 readyAnims.clear(); 648 } 649 650 // Now process all active animations. The return value from animationFrame() 651 // tells the handler whether it should now be ended 652 int numAnims = animations.size(); 653 int i = 0; 654 while (i < numAnims) { 655 ValueAnimator anim = animations.get(i); 656 if (anim.animationFrame(currentTime)) { 657 endingAnims.add(anim); 658 } 659 if (animations.size() == numAnims) { 660 ++i; 661 } else { 662 // An animation might be canceled or ended by client code 663 // during the animation frame. Check to see if this happened by 664 // seeing whether the current index is the same as it was before 665 // calling animationFrame(). Another approach would be to copy 666 // animations to a temporary list and process that list instead, 667 // but that entails garbage and processing overhead that would 668 // be nice to avoid. 669 --numAnims; 670 endingAnims.remove(anim); 671 } 672 } 673 if (endingAnims.size() > 0) { 674 for (i = 0; i < endingAnims.size(); ++i) { 675 endingAnims.get(i).endAnimation(); 676 } 677 endingAnims.clear(); 678 } 679 680 // If there are still active or delayed animations, call the handler again 681 // after the frameDelay 682 if (callAgain && (!animations.isEmpty() || !delayedAnims.isEmpty())) { 683 sendEmptyMessageDelayed(ANIMATION_FRAME, Math.max(0, sFrameDelay - 684 (AnimationUtils.currentAnimationTimeMillis() - currentTime))); 685 } 686 break; 687 } 688 } 689 } 690 691 /** 692 * The amount of time, in milliseconds, to delay starting the animation after 693 * {@link #start()} is called. 694 * 695 * @return the number of milliseconds to delay running the animation 696 */ 697 public long getStartDelay() { 698 return mStartDelay; 699 } 700 701 /** 702 * The amount of time, in milliseconds, to delay starting the animation after 703 * {@link #start()} is called. 704 705 * @param startDelay The amount of the delay, in milliseconds 706 */ 707 public void setStartDelay(long startDelay) { 708 this.mStartDelay = startDelay; 709 } 710 711 /** 712 * The amount of time, in milliseconds, between each frame of the animation. This is a 713 * requested time that the animation will attempt to honor, but the actual delay between 714 * frames may be different, depending on system load and capabilities. This is a static 715 * function because the same delay will be applied to all animations, since they are all 716 * run off of a single timing loop. 717 * 718 * @return the requested time between frames, in milliseconds 719 */ 720 public static long getFrameDelay() { 721 return sFrameDelay; 722 } 723 724 /** 725 * The amount of time, in milliseconds, between each frame of the animation. This is a 726 * requested time that the animation will attempt to honor, but the actual delay between 727 * frames may be different, depending on system load and capabilities. This is a static 728 * function because the same delay will be applied to all animations, since they are all 729 * run off of a single timing loop. 730 * 731 * @param frameDelay the requested time between frames, in milliseconds 732 */ 733 public static void setFrameDelay(long frameDelay) { 734 sFrameDelay = frameDelay; 735 } 736 737 /** 738 * The most recent value calculated by this <code>ValueAnimator</code> when there is just one 739 * property being animated. This value is only sensible while the animation is running. The main 740 * purpose for this read-only property is to retrieve the value from the <code>ValueAnimator</code> 741 * during a call to {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which 742 * is called during each animation frame, immediately after the value is calculated. 743 * 744 * @return animatedValue The value most recently calculated by this <code>ValueAnimator</code> for 745 * the single property being animated. If there are several properties being animated 746 * (specified by several PropertyValuesHolder objects in the constructor), this function 747 * returns the animated value for the first of those objects. 748 */ 749 public Object getAnimatedValue() { 750 if (mValues != null && mValues.length > 0) { 751 return mValues[0].getAnimatedValue(); 752 } 753 // Shouldn't get here; should always have values unless ValueAnimator was set up wrong 754 return null; 755 } 756 757 /** 758 * The most recent value calculated by this <code>ValueAnimator</code> for <code>propertyName</code>. 759 * The main purpose for this read-only property is to retrieve the value from the 760 * <code>ValueAnimator</code> during a call to 761 * {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which 762 * is called during each animation frame, immediately after the value is calculated. 763 * 764 * @return animatedValue The value most recently calculated for the named property 765 * by this <code>ValueAnimator</code>. 766 */ 767 public Object getAnimatedValue(String propertyName) { 768 PropertyValuesHolder valuesHolder = mValuesMap.get(propertyName); 769 if (valuesHolder != null) { 770 return valuesHolder.getAnimatedValue(); 771 } else { 772 // At least avoid crashing if called with bogus propertyName 773 return null; 774 } 775 } 776 777 /** 778 * Sets how many times the animation should be repeated. If the repeat 779 * count is 0, the animation is never repeated. If the repeat count is 780 * greater than 0 or {@link #INFINITE}, the repeat mode will be taken 781 * into account. The repeat count is 0 by default. 782 * 783 * @param value the number of times the animation should be repeated 784 */ 785 public void setRepeatCount(int value) { 786 mRepeatCount = value; 787 } 788 /** 789 * Defines how many times the animation should repeat. The default value 790 * is 0. 791 * 792 * @return the number of times the animation should repeat, or {@link #INFINITE} 793 */ 794 public int getRepeatCount() { 795 return mRepeatCount; 796 } 797 798 /** 799 * Defines what this animation should do when it reaches the end. This 800 * setting is applied only when the repeat count is either greater than 801 * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}. 802 * 803 * @param value {@link #RESTART} or {@link #REVERSE} 804 */ 805 public void setRepeatMode(int value) { 806 mRepeatMode = value; 807 } 808 809 /** 810 * Defines what this animation should do when it reaches the end. 811 * 812 * @return either one of {@link #REVERSE} or {@link #RESTART} 813 */ 814 public int getRepeatMode() { 815 return mRepeatMode; 816 } 817 818 /** 819 * Adds a listener to the set of listeners that are sent update events through the life of 820 * an animation. This method is called on all listeners for every frame of the animation, 821 * after the values for the animation have been calculated. 822 * 823 * @param listener the listener to be added to the current set of listeners for this animation. 824 */ 825 public void addUpdateListener(AnimatorUpdateListener listener) { 826 if (mUpdateListeners == null) { 827 mUpdateListeners = new ArrayList<AnimatorUpdateListener>(); 828 } 829 mUpdateListeners.add(listener); 830 } 831 832 /** 833 * Removes all listeners from the set listening to frame updates for this animation. 834 */ 835 public void removeAllUpdateListeners() { 836 if (mUpdateListeners == null) { 837 return; 838 } 839 mUpdateListeners.clear(); 840 mUpdateListeners = null; 841 } 842 843 /** 844 * Removes a listener from the set listening to frame updates for this animation. 845 * 846 * @param listener the listener to be removed from the current set of update listeners 847 * for this animation. 848 */ 849 public void removeUpdateListener(AnimatorUpdateListener listener) { 850 if (mUpdateListeners == null) { 851 return; 852 } 853 mUpdateListeners.remove(listener); 854 if (mUpdateListeners.size() == 0) { 855 mUpdateListeners = null; 856 } 857 } 858 859 860 /** 861 * The time interpolator used in calculating the elapsed fraction of this animation. The 862 * interpolator determines whether the animation runs with linear or non-linear motion, 863 * such as acceleration and deceleration. The default value is 864 * {@link android.view.animation.AccelerateDecelerateInterpolator} 865 * 866 * @param value the interpolator to be used by this animation. A value of <code>null</code> 867 * will result in linear interpolation. 868 */ 869 @Override 870 public void setInterpolator(TimeInterpolator value) { 871 if (value != null) { 872 mInterpolator = value; 873 } else { 874 mInterpolator = new LinearInterpolator(); 875 } 876 } 877 878 /** 879 * Returns the timing interpolator that this ValueAnimator uses. 880 * 881 * @return The timing interpolator for this ValueAnimator. 882 */ 883 public TimeInterpolator getInterpolator() { 884 return mInterpolator; 885 } 886 887 /** 888 * The type evaluator to be used when calculating the animated values of this animation. 889 * The system will automatically assign a float or int evaluator based on the type 890 * of <code>startValue</code> and <code>endValue</code> in the constructor. But if these values 891 * are not one of these primitive types, or if different evaluation is desired (such as is 892 * necessary with int values that represent colors), a custom evaluator needs to be assigned. 893 * For example, when running an animation on color values, the {@link ArgbEvaluator} 894 * should be used to get correct RGB color interpolation. 895 * 896 * <p>If this ValueAnimator has only one set of values being animated between, this evaluator 897 * will be used for that set. If there are several sets of values being animated, which is 898 * the case if PropertyValuesHOlder objects were set on the ValueAnimator, then the evaluator 899 * is assigned just to the first PropertyValuesHolder object.</p> 900 * 901 * @param value the evaluator to be used this animation 902 */ 903 public void setEvaluator(TypeEvaluator value) { 904 if (value != null && mValues != null && mValues.length > 0) { 905 mValues[0].setEvaluator(value); 906 } 907 } 908 909 /** 910 * Start the animation playing. This version of start() takes a boolean flag that indicates 911 * whether the animation should play in reverse. The flag is usually false, but may be set 912 * to true if called from the reverse() method. 913 * 914 * <p>The animation started by calling this method will be run on the thread that called 915 * this method. This thread should have a Looper on it (a runtime exception will be thrown if 916 * this is not the case). Also, if the animation will animate 917 * properties of objects in the view hierarchy, then the calling thread should be the UI 918 * thread for that view hierarchy.</p> 919 * 920 * @param playBackwards Whether the ValueAnimator should start playing in reverse. 921 */ 922 private void start(boolean playBackwards) { 923 if (Looper.myLooper() == null) { 924 throw new AndroidRuntimeException("Animators may only be run on Looper threads"); 925 } 926 mPlayingBackwards = playBackwards; 927 mCurrentIteration = 0; 928 mPlayingState = STOPPED; 929 mStarted = true; 930 mStartedDelay = false; 931 sPendingAnimations.get().add(this); 932 if (mStartDelay == 0) { 933 // This sets the initial value of the animation, prior to actually starting it running 934 setCurrentPlayTime(getCurrentPlayTime()); 935 mPlayingState = STOPPED; 936 mRunning = true; 937 938 if (mListeners != null) { 939 ArrayList<AnimatorListener> tmpListeners = 940 (ArrayList<AnimatorListener>) mListeners.clone(); 941 int numListeners = tmpListeners.size(); 942 for (int i = 0; i < numListeners; ++i) { 943 tmpListeners.get(i).onAnimationStart(this); 944 } 945 } 946 } 947 AnimationHandler animationHandler = sAnimationHandler.get(); 948 if (animationHandler == null) { 949 animationHandler = new AnimationHandler(); 950 sAnimationHandler.set(animationHandler); 951 } 952 animationHandler.sendEmptyMessage(ANIMATION_START); 953 } 954 955 @Override 956 public void start() { 957 start(false); 958 } 959 960 @Override 961 public void cancel() { 962 // Only cancel if the animation is actually running or has been started and is about 963 // to run 964 if (mPlayingState != STOPPED || sPendingAnimations.get().contains(this) || 965 sDelayedAnims.get().contains(this)) { 966 // Only notify listeners if the animator has actually started 967 if (mRunning && mListeners != null) { 968 ArrayList<AnimatorListener> tmpListeners = 969 (ArrayList<AnimatorListener>) mListeners.clone(); 970 for (AnimatorListener listener : tmpListeners) { 971 listener.onAnimationCancel(this); 972 } 973 } 974 endAnimation(); 975 } 976 } 977 978 @Override 979 public void end() { 980 if (!sAnimations.get().contains(this) && !sPendingAnimations.get().contains(this)) { 981 // Special case if the animation has not yet started; get it ready for ending 982 mStartedDelay = false; 983 startAnimation(); 984 } else if (!mInitialized) { 985 initAnimation(); 986 } 987 // The final value set on the target varies, depending on whether the animation 988 // was supposed to repeat an odd number of times 989 if (mRepeatCount > 0 && (mRepeatCount & 0x01) == 1) { 990 animateValue(0f); 991 } else { 992 animateValue(1f); 993 } 994 endAnimation(); 995 } 996 997 @Override 998 public boolean isRunning() { 999 return (mPlayingState == RUNNING || mRunning); 1000 } 1001 1002 @Override 1003 public boolean isStarted() { 1004 return mStarted; 1005 } 1006 1007 /** 1008 * Plays the ValueAnimator in reverse. If the animation is already running, 1009 * it will stop itself and play backwards from the point reached when reverse was called. 1010 * If the animation is not currently running, then it will start from the end and 1011 * play backwards. This behavior is only set for the current animation; future playing 1012 * of the animation will use the default behavior of playing forward. 1013 */ 1014 public void reverse() { 1015 mPlayingBackwards = !mPlayingBackwards; 1016 if (mPlayingState == RUNNING) { 1017 long currentTime = AnimationUtils.currentAnimationTimeMillis(); 1018 long currentPlayTime = currentTime - mStartTime; 1019 long timeLeft = mDuration - currentPlayTime; 1020 mStartTime = currentTime - timeLeft; 1021 } else { 1022 start(true); 1023 } 1024 } 1025 1026 /** 1027 * Called internally to end an animation by removing it from the animations list. Must be 1028 * called on the UI thread. 1029 */ 1030 private void endAnimation() { 1031 sAnimations.get().remove(this); 1032 sPendingAnimations.get().remove(this); 1033 sDelayedAnims.get().remove(this); 1034 mPlayingState = STOPPED; 1035 if (mRunning && mListeners != null) { 1036 ArrayList<AnimatorListener> tmpListeners = 1037 (ArrayList<AnimatorListener>) mListeners.clone(); 1038 int numListeners = tmpListeners.size(); 1039 for (int i = 0; i < numListeners; ++i) { 1040 tmpListeners.get(i).onAnimationEnd(this); 1041 } 1042 } 1043 mRunning = false; 1044 mStarted = false; 1045 } 1046 1047 /** 1048 * Called internally to start an animation by adding it to the active animations list. Must be 1049 * called on the UI thread. 1050 */ 1051 private void startAnimation() { 1052 initAnimation(); 1053 sAnimations.get().add(this); 1054 if (mStartDelay > 0 && mListeners != null) { 1055 // Listeners were already notified in start() if startDelay is 0; this is 1056 // just for delayed animations 1057 ArrayList<AnimatorListener> tmpListeners = 1058 (ArrayList<AnimatorListener>) mListeners.clone(); 1059 int numListeners = tmpListeners.size(); 1060 for (int i = 0; i < numListeners; ++i) { 1061 tmpListeners.get(i).onAnimationStart(this); 1062 } 1063 } 1064 } 1065 1066 /** 1067 * Internal function called to process an animation frame on an animation that is currently 1068 * sleeping through its <code>startDelay</code> phase. The return value indicates whether it 1069 * should be woken up and put on the active animations queue. 1070 * 1071 * @param currentTime The current animation time, used to calculate whether the animation 1072 * has exceeded its <code>startDelay</code> and should be started. 1073 * @return True if the animation's <code>startDelay</code> has been exceeded and the animation 1074 * should be added to the set of active animations. 1075 */ 1076 private boolean delayedAnimationFrame(long currentTime) { 1077 if (!mStartedDelay) { 1078 mStartedDelay = true; 1079 mDelayStartTime = currentTime; 1080 } else { 1081 long deltaTime = currentTime - mDelayStartTime; 1082 if (deltaTime > mStartDelay) { 1083 // startDelay ended - start the anim and record the 1084 // mStartTime appropriately 1085 mStartTime = currentTime - (deltaTime - mStartDelay); 1086 mPlayingState = RUNNING; 1087 return true; 1088 } 1089 } 1090 return false; 1091 } 1092 1093 /** 1094 * This internal function processes a single animation frame for a given animation. The 1095 * currentTime parameter is the timing pulse sent by the handler, used to calculate the 1096 * elapsed duration, and therefore 1097 * the elapsed fraction, of the animation. The return value indicates whether the animation 1098 * should be ended (which happens when the elapsed time of the animation exceeds the 1099 * animation's duration, including the repeatCount). 1100 * 1101 * @param currentTime The current time, as tracked by the static timing handler 1102 * @return true if the animation's duration, including any repetitions due to 1103 * <code>repeatCount</code> has been exceeded and the animation should be ended. 1104 */ 1105 boolean animationFrame(long currentTime) { 1106 boolean done = false; 1107 1108 if (mPlayingState == STOPPED) { 1109 mPlayingState = RUNNING; 1110 if (mSeekTime < 0) { 1111 mStartTime = currentTime; 1112 } else { 1113 mStartTime = currentTime - mSeekTime; 1114 // Now that we're playing, reset the seek time 1115 mSeekTime = -1; 1116 } 1117 } 1118 switch (mPlayingState) { 1119 case RUNNING: 1120 case SEEKED: 1121 float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f; 1122 if (fraction >= 1f) { 1123 if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) { 1124 // Time to repeat 1125 if (mListeners != null) { 1126 int numListeners = mListeners.size(); 1127 for (int i = 0; i < numListeners; ++i) { 1128 mListeners.get(i).onAnimationRepeat(this); 1129 } 1130 } 1131 if (mRepeatMode == REVERSE) { 1132 mPlayingBackwards = mPlayingBackwards ? false : true; 1133 } 1134 mCurrentIteration += (int)fraction; 1135 fraction = fraction % 1f; 1136 mStartTime += mDuration; 1137 } else { 1138 done = true; 1139 fraction = Math.min(fraction, 1.0f); 1140 } 1141 } 1142 if (mPlayingBackwards) { 1143 fraction = 1f - fraction; 1144 } 1145 animateValue(fraction); 1146 break; 1147 } 1148 1149 return done; 1150 } 1151 1152 /** 1153 * Returns the current animation fraction, which is the elapsed/interpolated fraction used in 1154 * the most recent frame update on the animation. 1155 * 1156 * @return Elapsed/interpolated fraction of the animation. 1157 */ 1158 public float getAnimatedFraction() { 1159 return mCurrentFraction; 1160 } 1161 1162 /** 1163 * This method is called with the elapsed fraction of the animation during every 1164 * animation frame. This function turns the elapsed fraction into an interpolated fraction 1165 * and then into an animated value (from the evaluator. The function is called mostly during 1166 * animation updates, but it is also called when the <code>end()</code> 1167 * function is called, to set the final value on the property. 1168 * 1169 * <p>Overrides of this method must call the superclass to perform the calculation 1170 * of the animated value.</p> 1171 * 1172 * @param fraction The elapsed fraction of the animation. 1173 */ 1174 void animateValue(float fraction) { 1175 fraction = mInterpolator.getInterpolation(fraction); 1176 mCurrentFraction = fraction; 1177 int numValues = mValues.length; 1178 for (int i = 0; i < numValues; ++i) { 1179 mValues[i].calculateValue(fraction); 1180 } 1181 if (mUpdateListeners != null) { 1182 int numListeners = mUpdateListeners.size(); 1183 for (int i = 0; i < numListeners; ++i) { 1184 mUpdateListeners.get(i).onAnimationUpdate(this); 1185 } 1186 } 1187 } 1188 1189 @Override 1190 public ValueAnimator clone() { 1191 final ValueAnimator anim = (ValueAnimator) super.clone(); 1192 if (mUpdateListeners != null) { 1193 ArrayList<AnimatorUpdateListener> oldListeners = mUpdateListeners; 1194 anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>(); 1195 int numListeners = oldListeners.size(); 1196 for (int i = 0; i < numListeners; ++i) { 1197 anim.mUpdateListeners.add(oldListeners.get(i)); 1198 } 1199 } 1200 anim.mSeekTime = -1; 1201 anim.mPlayingBackwards = false; 1202 anim.mCurrentIteration = 0; 1203 anim.mInitialized = false; 1204 anim.mPlayingState = STOPPED; 1205 anim.mStartedDelay = false; 1206 PropertyValuesHolder[] oldValues = mValues; 1207 if (oldValues != null) { 1208 int numValues = oldValues.length; 1209 anim.mValues = new PropertyValuesHolder[numValues]; 1210 anim.mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues); 1211 for (int i = 0; i < numValues; ++i) { 1212 PropertyValuesHolder newValuesHolder = oldValues[i].clone(); 1213 anim.mValues[i] = newValuesHolder; 1214 anim.mValuesMap.put(newValuesHolder.getPropertyName(), newValuesHolder); 1215 } 1216 } 1217 return anim; 1218 } 1219 1220 /** 1221 * Implementors of this interface can add themselves as update listeners 1222 * to an <code>ValueAnimator</code> instance to receive callbacks on every animation 1223 * frame, after the current frame's values have been calculated for that 1224 * <code>ValueAnimator</code>. 1225 */ 1226 public static interface AnimatorUpdateListener { 1227 /** 1228 * <p>Notifies the occurrence of another frame of the animation.</p> 1229 * 1230 * @param animation The animation which was repeated. 1231 */ 1232 void onAnimationUpdate(ValueAnimator animation); 1233 1234 } 1235 1236 /** 1237 * Return the number of animations currently running. 1238 * 1239 * Used by StrictMode internally to annotate violations. Only 1240 * called on the main thread. 1241 * 1242 * @hide 1243 */ 1244 public static int getCurrentAnimationsCount() { 1245 return sAnimations.get().size(); 1246 } 1247 1248 /** 1249 * Clear all animations on this thread, without canceling or ending them. 1250 * This should be used with caution. 1251 * 1252 * @hide 1253 */ 1254 public static void clearAllAnimations() { 1255 sAnimations.get().clear(); 1256 sPendingAnimations.get().clear(); 1257 sDelayedAnims.get().clear(); 1258 } 1259 1260 @Override 1261 public String toString() { 1262 String returnVal = "ValueAnimator@" + Integer.toHexString(hashCode()); 1263 if (mValues != null) { 1264 for (int i = 0; i < mValues.length; ++i) { 1265 returnVal += "\n " + mValues[i].toString(); 1266 } 1267 } 1268 return returnVal; 1269 } 1270} 1271