Animator.java revision 17fb4b0d1cfbad1f026fec704c86640f070b4c2f
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.Message; 21import android.view.animation.AccelerateDecelerateInterpolator; 22import android.view.animation.AnimationUtils; 23import android.view.animation.Interpolator; 24 25import java.util.ArrayList; 26 27/** 28 * This class provides a simple timing engine for running animations 29 * which calculate animated values and set them on target objects. 30 * 31 * There is a single timing pulse that all animations use. It runs in a 32 * custom handler to ensure that property changes happen on the UI thread. 33 */ 34public class Animator extends Animatable { 35 36 /** 37 * Internal constants 38 */ 39 40 /* 41 * The default amount of time in ms between animation frames 42 */ 43 private static final long DEFAULT_FRAME_DELAY = 30; 44 45 /** 46 * Messages sent to timing handler: START is sent when an animation first begins, FRAME is sent 47 * by the handler to itself to process the next animation frame 48 */ 49 private static final int ANIMATION_START = 0; 50 private static final int ANIMATION_FRAME = 1; 51 52 /** 53 * Values used with internal variable mPlayingState to indicate the current state of an 54 * animation. 55 */ 56 private static final int STOPPED = 0; // Not yet playing 57 private static final int RUNNING = 1; // Playing normally 58 private static final int CANCELED = 2; // cancel() called - need to end it 59 private static final int ENDED = 3; // end() called - need to end it 60 61 /** 62 * Internal variables 63 */ 64 65 66 // The first time that the animation's animateFrame() method is called. This time is used to 67 // determine elapsed time (and therefore the elapsed fraction) in subsequent calls 68 // to animateFrame() 69 private long mStartTime; 70 71 // The static sAnimationHandler processes the internal timing loop on which all animations 72 // are based 73 private static AnimationHandler sAnimationHandler; 74 75 // The static list of all active animations 76 private static final ArrayList<Animator> sAnimations = new ArrayList<Animator>(); 77 78 // The set of animations to be started on the next animation frame 79 private static final ArrayList<Animator> sPendingAnimations = new ArrayList<Animator>(); 80 81 // The time interpolator to be used if none is set on the animation 82 private static final Interpolator sDefaultInterpolator = new AccelerateDecelerateInterpolator(); 83 84 // type evaluators for the three primitive types handled by this implementation 85 private static final TypeEvaluator sIntEvaluator = new IntEvaluator(); 86 private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator(); 87 private static final TypeEvaluator sDoubleEvaluator = new DoubleEvaluator(); 88 89 /** 90 * Used to indicate whether the animation is currently playing in reverse. This causes the 91 * elapsed fraction to be inverted to calculate the appropriate values. 92 */ 93 private boolean mPlayingBackwards = false; 94 95 /** 96 * This variable tracks the current iteration that is playing. When mCurrentIteration exceeds the 97 * repeatCount (if repeatCount!=INFINITE), the animation ends 98 */ 99 private int mCurrentIteration = 0; 100 101 /** 102 * Tracks whether a startDelay'd animation has begun playing through the startDelay. 103 */ 104 private boolean mStartedDelay = false; 105 106 /** 107 * Tracks the time at which the animation began playing through its startDelay. This is 108 * different from the mStartTime variable, which is used to track when the animation became 109 * active (which is when the startDelay expired and the animation was added to the active 110 * animations list). 111 */ 112 private long mDelayStartTime; 113 114 /** 115 * Flag that represents the current state of the animation. Used to figure out when to start 116 * an animation (if state == STOPPED). Also used to end an animation that 117 * has been cancel()'d or end()'d since the last animation frame. Possible values are 118 * STOPPED, RUNNING, ENDED, CANCELED. 119 */ 120 private int mPlayingState = STOPPED; 121 122 /** 123 * Internal collections used to avoid set collisions as animations start and end while being 124 * processed. 125 */ 126 private static final ArrayList<Animator> sEndingAnims = new ArrayList<Animator>(); 127 private static final ArrayList<Animator> sDelayedAnims = new ArrayList<Animator>(); 128 private static final ArrayList<Animator> sReadyAnims = new ArrayList<Animator>(); 129 130 // 131 // Backing variables 132 // 133 134 // How long the animation should last in ms 135 private long mDuration; 136 137 // The value that the animation should start from, set in the constructor 138 private Object mValueFrom; 139 140 // The value that the animation should animate to, set in the constructor 141 private Object mValueTo; 142 143 // The amount of time in ms to delay starting the animation after start() is called 144 private long mStartDelay = 0; 145 146 // The number of milliseconds between animation frames 147 private static long sFrameDelay = DEFAULT_FRAME_DELAY; 148 149 // The number of times the animation will repeat. The default is 0, which means the animation 150 // will play only once 151 private int mRepeatCount = 0; 152 153 /** 154 * The type of repetition that will occur when repeatMode is nonzero. RESTART means the 155 * animation will start from the beginning on every new cycle. REVERSE means the animation 156 * will reverse directions on each iteration. 157 */ 158 private int mRepeatMode = RESTART; 159 160 /** 161 * The time interpolator to be used. The elapsed fraction of the animation will be passed 162 * through this interpolator to calculate the interpolated fraction, which is then used to 163 * calculate the animated values. 164 */ 165 private Interpolator mInterpolator = sDefaultInterpolator; 166 167 /** 168 * The type evaluator used to calculate the animated values. This evaluator is determined 169 * automatically based on the type of the start/end objects passed into the constructor, 170 * but the system only knows about the primitive types int, double, and float. Any other 171 * type will need to set the evaluator to a custom evaluator for that type. 172 */ 173 private TypeEvaluator mEvaluator; 174 175 /** 176 * The set of listeners to be sent events through the life of an animation. 177 */ 178 private ArrayList<AnimatorUpdateListener> mUpdateListeners = null; 179 180 /** 181 * The current value calculated by the animation. The value is calculated in animateFraction(), 182 * prior to calling the setter (if set) and sending out the onAnimationUpdate() callback 183 * to the update listeners. 184 */ 185 private Object mAnimatedValue = null; 186 187 /** 188 * The type of the values, as determined by the valueFrom/valueTo properties. 189 */ 190 Class mValueType; 191 192 /** 193 * Public constants 194 */ 195 196 /** 197 * When the animation reaches the end and <code>repeatCount</code> is INFINITE 198 * or a positive value, the animation restarts from the beginning. 199 */ 200 public static final int RESTART = 1; 201 /** 202 * When the animation reaches the end and <code>repeatCount</code> is INFINITE 203 * or a positive value, the animation reverses direction on every iteration. 204 */ 205 public static final int REVERSE = 2; 206 /** 207 * This value used used with the {@link #setRepeatCount(int)} property to repeat 208 * the animation indefinitely. 209 */ 210 public static final int INFINITE = -1; 211 212 private Animator(long duration, Object valueFrom, Object valueTo, Class valueType) { 213 mDuration = duration; 214 mValueFrom = valueFrom; 215 mValueTo= valueTo; 216 this.mValueType = valueType; 217 } 218 219 /** 220 * This function is called immediately before processing the first animation 221 * frame of an animation. If there is a nonzero <code>startDelay</code>, the 222 * function is called after that delay ends. 223 * It takes care of the final initialization steps for the 224 * animation. 225 * 226 * <p>Overrides of this method should call the superclass method to ensure 227 * that internal mechanisms for the animation are set up correctly.</p> 228 */ 229 void initAnimation() { 230 if (mEvaluator == null) { 231 mEvaluator = (mValueType == int.class) ? sIntEvaluator : 232 (mValueType == double.class) ? sDoubleEvaluator : sFloatEvaluator; 233 } 234 mPlayingBackwards = false; 235 mCurrentIteration = 0; 236 } 237 238 /** 239 * A constructor that takes <code>float</code> values. 240 * 241 * @param duration The length of the animation, in milliseconds. 242 * @param valueFrom The initial value of the property when the animation begins. 243 * @param valueTo The value to which the property will animate. 244 */ 245 public Animator(long duration, float valueFrom, float valueTo) { 246 this(duration, valueFrom, valueTo, float.class); 247 } 248 249 /** 250 * A constructor that takes <code>int</code> values. 251 * 252 * @param duration The length of the animation, in milliseconds. 253 * @param valueFrom The initial value of the property when the animation begins. 254 * @param valueTo The value to which the property will animate. 255 */ 256 public Animator(long duration, int valueFrom, int valueTo) { 257 this(duration, valueFrom, valueTo, int.class); 258 } 259 260 /** 261 * A constructor that takes <code>double</code> values. 262 * 263 * @param duration The length of the animation, in milliseconds. 264 * @param valueFrom The initial value of the property when the animation begins. 265 * @param valueTo The value to which the property will animate. 266 */ 267 public Animator(long duration, double valueFrom, double valueTo) { 268 this(duration, valueFrom, valueTo, double.class); 269 } 270 271 /** 272 * A constructor that takes <code>Object</code> values. 273 * 274 * @param duration The length of the animation, in milliseconds. 275 * @param valueFrom The initial value of the property when the animation begins. 276 * @param valueTo The value to which the property will animate. 277 */ 278 public Animator(long duration, Object valueFrom, Object valueTo) { 279 this(duration, valueFrom, valueTo, 280 (valueFrom != null) ? valueFrom.getClass() : valueTo.getClass()); 281 } 282 283 /** 284 * This custom, static handler handles the timing pulse that is shared by 285 * all active animations. This approach ensures that the setting of animation 286 * values will happen on the UI thread and that all animations will share 287 * the same times for calculating their values, which makes synchronizing 288 * animations possible. 289 * 290 */ 291 private static class AnimationHandler extends Handler { 292 /** 293 * There are only two messages that we care about: ANIMATION_START and 294 * ANIMATION_FRAME. The START message is sent when an animation's start() 295 * method is called. It cannot start synchronously when start() is called 296 * because the call may be on the wrong thread, and it would also not be 297 * synchronized with other animations because it would not start on a common 298 * timing pulse. So each animation sends a START message to the handler, which 299 * causes the handler to place the animation on the active animations queue and 300 * start processing frames for that animation. 301 * The FRAME message is the one that is sent over and over while there are any 302 * active animations to process. 303 */ 304 @Override 305 public void handleMessage(Message msg) { 306 boolean callAgain = true; 307 switch (msg.what) { 308 // TODO: should we avoid sending frame message when starting if we 309 // were already running? 310 case ANIMATION_START: 311 if (sAnimations.size() > 0 || sDelayedAnims.size() > 0) { 312 callAgain = false; 313 } 314 // pendingAnims holds any animations that have requested to be started 315 // We're going to clear sPendingAnimations, but starting animation may 316 // cause more to be added to the pending list (for example, if one animation 317 // starting triggers another starting). So we loop until sPendingAnimations 318 // is empty. 319 while (sPendingAnimations.size() > 0) { 320 ArrayList<Animator> pendingCopy = 321 (ArrayList<Animator>) sPendingAnimations.clone(); 322 sPendingAnimations.clear(); 323 int count = pendingCopy.size(); 324 for (int i = 0; i < count; ++i) { 325 Animator anim = pendingCopy.get(i); 326 // If the animation has a startDelay, place it on the delayed list 327 if (anim.mStartDelay == 0) { 328 anim.startAnimation(); 329 } else { 330 sDelayedAnims.add(anim); 331 } 332 } 333 } 334 // fall through to process first frame of new animations 335 case ANIMATION_FRAME: 336 // currentTime holds the common time for all animations processed 337 // during this frame 338 long currentTime = AnimationUtils.currentAnimationTimeMillis(); 339 340 // First, process animations currently sitting on the delayed queue, adding 341 // them to the active animations if they are ready 342 int numDelayedAnims = sDelayedAnims.size(); 343 for (int i = 0; i < numDelayedAnims; ++i) { 344 Animator anim = sDelayedAnims.get(i); 345 if (anim.delayedAnimationFrame(currentTime)) { 346 sReadyAnims.add(anim); 347 } 348 } 349 int numReadyAnims = sReadyAnims.size(); 350 if (numReadyAnims > 0) { 351 for (int i = 0; i < numReadyAnims; ++i) { 352 Animator anim = sReadyAnims.get(i); 353 anim.startAnimation(); 354 sDelayedAnims.remove(anim); 355 } 356 sReadyAnims.clear(); 357 } 358 359 // Now process all active animations. The return value from animationFrame() 360 // tells the handler whether it should now be ended 361 int numAnims = sAnimations.size(); 362 for (int i = 0; i < numAnims; ++i) { 363 Animator anim = sAnimations.get(i); 364 if (anim.animationFrame(currentTime)) { 365 sEndingAnims.add(anim); 366 } 367 } 368 if (sEndingAnims.size() > 0) { 369 for (int i = 0; i < sEndingAnims.size(); ++i) { 370 sEndingAnims.get(i).endAnimation(); 371 } 372 sEndingAnims.clear(); 373 } 374 375 // If there are still active or delayed animations, call the handler again 376 // after the frameDelay 377 if (callAgain && (!sAnimations.isEmpty() || !sDelayedAnims.isEmpty())) { 378 sendEmptyMessageDelayed(ANIMATION_FRAME, sFrameDelay); 379 } 380 break; 381 } 382 } 383 } 384 385 /** 386 * The amount of time, in milliseconds, to delay starting the animation after 387 * {@link #start()} is called. 388 * 389 * @return the number of milliseconds to delay running the animation 390 */ 391 public long getStartDelay() { 392 return mStartDelay; 393 } 394 395 /** 396 * The amount of time, in milliseconds, to delay starting the animation after 397 * {@link #start()} is called. 398 399 * @param startDelay The amount of the delay, in milliseconds 400 */ 401 public void setStartDelay(long startDelay) { 402 this.mStartDelay = startDelay; 403 } 404 405 /** 406 * The amount of time, in milliseconds, between each frame of the animation. This is a 407 * requested time that the animation will attempt to honor, but the actual delay between 408 * frames may be different, depending on system load and capabilities. This is a static 409 * function because the same delay will be applied to all animations, since they are all 410 * run off of a single timing loop. 411 * 412 * @return the requested time between frames, in milliseconds 413 */ 414 public static long getFrameDelay() { 415 return sFrameDelay; 416 } 417 418 /** 419 * Gets the value that this animation will start from. 420 * 421 * @return Object The starting value for the animation. 422 */ 423 public Object getValueFrom() { 424 return mValueFrom; 425 } 426 427 /** 428 * Sets the value that this animation will start from. 429 */ 430 public void setValueFrom(Object valueFrom) { 431 mValueFrom = valueFrom; 432 } 433 434 /** 435 * Gets the value that this animation will animate to. 436 * 437 * @return Object The ending value for the animation. 438 */ 439 public Object getValueTo() { 440 return mValueTo; 441 } 442 443 /** 444 * Sets the value that this animation will animate to. 445 * 446 * @return Object The ending value for the animation. 447 */ 448 public void setValueTo(Object valueTo) { 449 mValueTo = valueTo; 450 } 451 452 /** 453 * The amount of time, in milliseconds, between each frame of the animation. This is a 454 * requested time that the animation will attempt to honor, but the actual delay between 455 * frames may be different, depending on system load and capabilities. This is a static 456 * function because the same delay will be applied to all animations, since they are all 457 * run off of a single timing loop. 458 * 459 * @param frameDelay the requested time between frames, in milliseconds 460 */ 461 public static void setFrameDelay(long frameDelay) { 462 sFrameDelay = frameDelay; 463 } 464 465 /** 466 * The most recent value calculated by this <code>Animator</code> for the property 467 * being animated. This value is only sensible while the animation is running. The main 468 * purpose for this read-only property is to retrieve the value from the <code>Animator</code> 469 * during a call to {@link AnimatorUpdateListener#onAnimationUpdate(Animator)}, which 470 * is called during each animation frame, immediately after the value is calculated. 471 * 472 * @return animatedValue The value most recently calculated by this <code>Animator</code> for 473 * the property specified in the constructor. 474 */ 475 public Object getAnimatedValue() { 476 return mAnimatedValue; 477 } 478 479 /** 480 * Sets how many times the animation should be repeated. If the repeat 481 * count is 0, the animation is never repeated. If the repeat count is 482 * greater than 0 or {@link #INFINITE}, the repeat mode will be taken 483 * into account. The repeat count is 0 by default. 484 * 485 * @param value the number of times the animation should be repeated 486 */ 487 public void setRepeatCount(int value) { 488 mRepeatCount = value; 489 } 490 /** 491 * Defines how many times the animation should repeat. The default value 492 * is 0. 493 * 494 * @return the number of times the animation should repeat, or {@link #INFINITE} 495 */ 496 public int getRepeatCount() { 497 return mRepeatCount; 498 } 499 500 /** 501 * Defines what this animation should do when it reaches the end. This 502 * setting is applied only when the repeat count is either greater than 503 * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}. 504 * 505 * @param value {@link #RESTART} or {@link #REVERSE} 506 */ 507 public void setRepeatMode(int value) { 508 mRepeatMode = value; 509 } 510 511 /** 512 * Defines what this animation should do when it reaches the end. 513 * 514 * @return either one of {@link #REVERSE} or {@link #RESTART} 515 */ 516 public int getRepeatMode() { 517 return mRepeatMode; 518 } 519 520 /** 521 * Adds a listener to the set of listeners that are sent update events through the life of 522 * an animation. This method is called on all listeners for every frame of the animation, 523 * after the values for the animation have been calculated. 524 * 525 * @param listener the listener to be added to the current set of listeners for this animation. 526 */ 527 public void addUpdateListener(AnimatorUpdateListener listener) { 528 if (mUpdateListeners == null) { 529 mUpdateListeners = new ArrayList<AnimatorUpdateListener>(); 530 } 531 mUpdateListeners.add(listener); 532 } 533 534 /** 535 * Removes a listener from the set listening to frame updates for this animation. 536 * 537 * @param listener the listener to be removed from the current set of update listeners 538 * for this animation. 539 */ 540 public void removeUpdateListener(AnimatorUpdateListener listener) { 541 if (mUpdateListeners == null) { 542 return; 543 } 544 mUpdateListeners.remove(listener); 545 if (mUpdateListeners.size() == 0) { 546 mUpdateListeners = null; 547 } 548 } 549 550 551 /** 552 * The time interpolator used in calculating the elapsed fraction of this animation. The 553 * interpolator determines whether the animation runs with linear or non-linear motion, 554 * such as acceleration and deceleration. The default value is 555 * {@link android.view.animation.AccelerateDecelerateInterpolator} 556 * 557 * @param value the interpolator to be used by this animation 558 */ 559 public void setInterpolator(Interpolator value) { 560 if (value != null) { 561 mInterpolator = value; 562 } 563 } 564 565 /** 566 * The type evaluator to be used when calculating the animated values of this animation. 567 * The system will automatically assign a float, int, or double evaluator based on the type 568 * of <code>startValue</code> and <code>endValue</code> in the constructor. But if these values 569 * are not one of these primitive types, or if different evaluation is desired (such as is 570 * necessary with int values that represent colors), a custom evaluator needs to be assigned. 571 * For example, when running an animation on color values, the {@link RGBEvaluator} 572 * should be used to get correct RGB color interpolation. 573 * 574 * @param value the evaluator to be used this animation 575 */ 576 public void setEvaluator(TypeEvaluator value) { 577 if (value != null) { 578 mEvaluator = value; 579 } 580 } 581 582 public void start() { 583 sPendingAnimations.add(this); 584 if (sAnimationHandler == null) { 585 sAnimationHandler = new AnimationHandler(); 586 } 587 // TODO: does this put too many messages on the queue if the handler 588 // is already running? 589 sAnimationHandler.sendEmptyMessage(ANIMATION_START); 590 } 591 592 public void cancel() { 593 if (mListeners != null) { 594 ArrayList<AnimatableListener> tmpListeners = 595 (ArrayList<AnimatableListener>) mListeners.clone(); 596 for (AnimatableListener listener : tmpListeners) { 597 listener.onAnimationCancel(this); 598 } 599 } 600 // Just set the CANCELED flag - this causes the animation to end the next time a frame 601 // is processed. 602 mPlayingState = CANCELED; 603 } 604 605 public void end() { 606 // Just set the ENDED flag - this causes the animation to end the next time a frame 607 // is processed. 608 mPlayingState = ENDED; 609 } 610 611 /** 612 * Called internally to end an animation by removing it from the animations list. Must be 613 * called on the UI thread. 614 */ 615 private void endAnimation() { 616 sAnimations.remove(this); 617 if (mListeners != null) { 618 ArrayList<AnimatableListener> tmpListeners = 619 (ArrayList<AnimatableListener>) mListeners.clone(); 620 for (AnimatableListener listener : tmpListeners) { 621 listener.onAnimationEnd(this); 622 } 623 } 624 mPlayingState = STOPPED; 625 } 626 627 /** 628 * Called internally to start an animation by adding it to the active animations list. Must be 629 * called on the UI thread. 630 */ 631 private void startAnimation() { 632 initAnimation(); 633 sAnimations.add(this); 634 if (mListeners != null) { 635 ArrayList<AnimatableListener> tmpListeners = 636 (ArrayList<AnimatableListener>) mListeners.clone(); 637 for (AnimatableListener listener : tmpListeners) { 638 listener.onAnimationStart(this); 639 } 640 } 641 } 642 643 /** 644 * Internal function called to process an animation frame on an animation that is currently 645 * sleeping through its <code>startDelay</code> phase. The return value indicates whether it 646 * should be woken up and put on the active animations queue. 647 * 648 * @param currentTime The current animation time, used to calculate whether the animation 649 * has exceeded its <code>startDelay</code> and should be started. 650 * @return True if the animation's <code>startDelay</code> has been exceeded and the animation 651 * should be added to the set of active animations. 652 */ 653 private boolean delayedAnimationFrame(long currentTime) { 654 if (!mStartedDelay) { 655 mStartedDelay = true; 656 mDelayStartTime = currentTime; 657 } else { 658 long deltaTime = currentTime - mDelayStartTime; 659 if (deltaTime > mStartDelay) { 660 // startDelay ended - start the anim and record the 661 // mStartTime appropriately 662 mStartTime = currentTime - (deltaTime - mStartDelay); 663 mPlayingState = RUNNING; 664 return true; 665 } 666 } 667 return false; 668 } 669 670 /** 671 * This internal function processes a single animation frame for a given animation. The 672 * currentTime parameter is the timing pulse sent by the handler, used to calculate the 673 * elapsed duration, and therefore 674 * the elapsed fraction, of the animation. The return value indicates whether the animation 675 * should be ended (which happens when the elapsed time of the animation exceeds the 676 * animation's duration, including the repeatCount). 677 * 678 * @param currentTime The current time, as tracked by the static timing handler 679 * @return true if the animation's duration, including any repetitions due to 680 * <code>repeatCount</code> has been exceeded and the animation should be ended. 681 */ 682 private boolean animationFrame(long currentTime) { 683 684 boolean done = false; 685 686 if (mPlayingState == STOPPED) { 687 mPlayingState = RUNNING; 688 mStartTime = currentTime; 689 } 690 switch (mPlayingState) { 691 case RUNNING: 692 float fraction = (float)(currentTime - mStartTime) / mDuration; 693 if (fraction >= 1f) { 694 if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) { 695 // Time to repeat 696 if (mListeners != null) { 697 for (AnimatableListener listener : mListeners) { 698 listener.onAnimationRepeat(this); 699 } 700 } 701 ++mCurrentIteration; 702 if (mRepeatMode == REVERSE) { 703 mPlayingBackwards = mPlayingBackwards ? false : true; 704 } 705 // TODO: doesn't account for fraction going Wayyyyy over 1, like 2+ 706 fraction = fraction - 1f; 707 mStartTime += mDuration; 708 } else { 709 done = true; 710 fraction = Math.min(fraction, 1.0f); 711 } 712 } 713 if (mPlayingBackwards) { 714 fraction = 1f - fraction; 715 } 716 animateValue(fraction); 717 break; 718 case ENDED: 719 // The final value set on the target varies, depending on whether the animation 720 // was supposed to repeat an odd number of times 721 if (mRepeatCount > 0 && (mRepeatCount & 0x01) == 1) { 722 animateValue(0f); 723 } else { 724 animateValue(1f); 725 } 726 // Fall through to set done flag 727 case CANCELED: 728 done = true; 729 break; 730 } 731 732 return done; 733 } 734 735 /** 736 * This method is called with the elapsed fraction of the animation during every 737 * animation frame. This function turns the elapsed fraction into an interpolated fraction 738 * and then into an animated value (from the evaluator. The function is called mostly during 739 * animation updates, but it is also called when the <code>end()</code> 740 * function is called, to set the final value on the property. 741 * 742 * <p>Overrides of this method must call the superclass to perform the calculation 743 * of the animated value.</p> 744 * 745 * @param fraction The elapsed fraction of the animation. 746 */ 747 void animateValue(float fraction) { 748 fraction = mInterpolator.getInterpolation(fraction); 749 mAnimatedValue = mEvaluator.evaluate(fraction, mValueFrom, mValueTo); 750 if (mUpdateListeners != null) { 751 int numListeners = mUpdateListeners.size(); 752 for (int i = 0; i < numListeners; ++i) { 753 mUpdateListeners.get(i).onAnimationUpdate(this); 754 } 755 } 756 } 757 758 /** 759 * Implementors of this interface can add themselves as update listeners 760 * to an <code>Animator</code> instance to receive callbacks on every animation 761 * frame, after the current frame's values have been calculated for that 762 * <code>Animator</code>. 763 */ 764 public static interface AnimatorUpdateListener { 765 /** 766 * <p>Notifies the occurrence of another frame of the animation.</p> 767 * 768 * @param animation The animation which was repeated. 769 */ 770 void onAnimationUpdate(Animator animation); 771 772 } 773}