Animation.java revision 4766defdd0778d7e0a656179d03a4865a9a40523
1/* 2 * Copyright (C) 2006 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.view.animation; 18 19import android.content.Context; 20import android.content.res.TypedArray; 21import android.util.AttributeSet; 22import android.util.TypedValue; 23import android.graphics.RectF; 24 25/** 26 * Abstraction for an Animation that can be applied to Views, Surfaces, or 27 * other objects. See the {@link android.view.animation animation package 28 * description file}. 29 */ 30public abstract class Animation implements Cloneable { 31 /** 32 * Repeat the animation indefinitely. 33 */ 34 public static final int INFINITE = -1; 35 36 /** 37 * When the animation reaches the end and the repeat count is INFINTE_REPEAT 38 * or a positive value, the animation restarts from the beginning. 39 */ 40 public static final int RESTART = 1; 41 42 /** 43 * When the animation reaches the end and the repeat count is INFINTE_REPEAT 44 * or a positive value, the animation plays backward (and then forward again). 45 */ 46 public static final int REVERSE = 2; 47 48 /** 49 * Can be used as the start time to indicate the start time should be the current 50 * time when {@link #getTransformation(long, Transformation)} is invoked for the 51 * first animation frame. This can is useful for short animations. 52 */ 53 public static final int START_ON_FIRST_FRAME = -1; 54 55 /** 56 * The specified dimension is an absolute number of pixels. 57 */ 58 public static final int ABSOLUTE = 0; 59 60 /** 61 * The specified dimension holds a float and should be multiplied by the 62 * height or width of the object being animated. 63 */ 64 public static final int RELATIVE_TO_SELF = 1; 65 66 /** 67 * The specified dimension holds a float and should be multiplied by the 68 * height or width of the parent of the object being animated. 69 */ 70 public static final int RELATIVE_TO_PARENT = 2; 71 72 /** 73 * Requests that the content being animated be kept in its current Z 74 * order. 75 */ 76 public static final int ZORDER_NORMAL = 0; 77 78 /** 79 * Requests that the content being animated be forced on top of all other 80 * content for the duration of the animation. 81 */ 82 public static final int ZORDER_TOP = 1; 83 84 /** 85 * Requests that the content being animated be forced under all other 86 * content for the duration of the animation. 87 */ 88 public static final int ZORDER_BOTTOM = -1; 89 90 /** 91 * Set by {@link #getTransformation(long, Transformation)} when the animation ends. 92 */ 93 boolean mEnded = false; 94 95 /** 96 * Set by {@link #getTransformation(long, Transformation)} when the animation starts. 97 */ 98 boolean mStarted = false; 99 100 /** 101 * Set by {@link #getTransformation(long, Transformation)} when the animation repeats 102 * in REVERSE mode. 103 */ 104 boolean mCycleFlip = false; 105 106 /** 107 * This value must be set to true by {@link #initialize(int, int, int, int)}. It 108 * indicates the animation was successfully initialized and can be played. 109 */ 110 boolean mInitialized = false; 111 112 /** 113 * Indicates whether the animation transformation should be applied before the 114 * animation starts. 115 */ 116 boolean mFillBefore = true; 117 118 /** 119 * Indicates whether the animation transformation should be applied after the 120 * animation ends. 121 */ 122 boolean mFillAfter = false; 123 124 /** 125 * Indicates whether fillAfter should be taken into account. 126 */ 127 boolean mFillEnabled = false; 128 129 /** 130 * The time in milliseconds at which the animation must start; 131 */ 132 long mStartTime = -1; 133 134 /** 135 * The delay in milliseconds after which the animation must start. When the 136 * start offset is > 0, the start time of the animation is startTime + startOffset. 137 */ 138 long mStartOffset; 139 140 /** 141 * The duration of one animation cycle in milliseconds. 142 */ 143 long mDuration; 144 145 /** 146 * The number of times the animation must repeat. By default, an animation repeats 147 * indefinitely. 148 */ 149 int mRepeatCount = 0; 150 151 /** 152 * Indicates how many times the animation was repeated. 153 */ 154 int mRepeated = 0; 155 156 /** 157 * The behavior of the animation when it repeats. The repeat mode is either 158 * {@link #RESTART} or {@link #REVERSE}. 159 * 160 */ 161 int mRepeatMode = RESTART; 162 163 /** 164 * The interpolator used by the animation to smooth the movement. 165 */ 166 Interpolator mInterpolator; 167 168 /** 169 * The animation listener to be notified when the animation starts, ends or repeats. 170 */ 171 AnimationListener mListener; 172 173 /** 174 * Desired Z order mode during animation. 175 */ 176 private int mZAdjustment; 177 178 /** 179 * Don't animate the wallpaper. 180 */ 181 private boolean mDetachWallpaper = false; 182 183 private boolean mMore = true; 184 private boolean mOneMoreTime = true; 185 186 RectF mPreviousRegion = new RectF(); 187 RectF mRegion = new RectF(); 188 Transformation mTransformation = new Transformation(); 189 Transformation mPreviousTransformation = new Transformation(); 190 191 /** 192 * Creates a new animation with a duration of 0ms, the default interpolator, with 193 * fillBefore set to true and fillAfter set to false 194 */ 195 public Animation() { 196 ensureInterpolator(); 197 } 198 199 /** 200 * Creates a new animation whose parameters come from the specified context and 201 * attributes set. 202 * 203 * @param context the application environment 204 * @param attrs the set of attributes holding the animation parameters 205 */ 206 public Animation(Context context, AttributeSet attrs) { 207 TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Animation); 208 209 setDuration((long) a.getInt(com.android.internal.R.styleable.Animation_duration, 0)); 210 setStartOffset((long) a.getInt(com.android.internal.R.styleable.Animation_startOffset, 0)); 211 212 setFillEnabled(a.getBoolean(com.android.internal.R.styleable.Animation_fillEnabled, mFillEnabled)); 213 setFillBefore(a.getBoolean(com.android.internal.R.styleable.Animation_fillBefore, mFillBefore)); 214 setFillAfter(a.getBoolean(com.android.internal.R.styleable.Animation_fillAfter, mFillAfter)); 215 216 final int resID = a.getResourceId(com.android.internal.R.styleable.Animation_interpolator, 0); 217 if (resID > 0) { 218 setInterpolator(context, resID); 219 } 220 221 setRepeatCount(a.getInt(com.android.internal.R.styleable.Animation_repeatCount, mRepeatCount)); 222 setRepeatMode(a.getInt(com.android.internal.R.styleable.Animation_repeatMode, RESTART)); 223 224 setZAdjustment(a.getInt(com.android.internal.R.styleable.Animation_zAdjustment, ZORDER_NORMAL)); 225 226 setDetachWallpaper(a.getBoolean(com.android.internal.R.styleable.Animation_detachWallpaper, false)); 227 228 ensureInterpolator(); 229 230 a.recycle(); 231 } 232 233 @Override 234 protected Animation clone() throws CloneNotSupportedException { 235 final Animation animation = (Animation) super.clone(); 236 animation.mPreviousRegion = new RectF(); 237 animation.mRegion = new RectF(); 238 animation.mTransformation = new Transformation(); 239 animation.mPreviousTransformation = new Transformation(); 240 return animation; 241 } 242 243 /** 244 * Reset the initialization state of this animation. 245 * 246 * @see #initialize(int, int, int, int) 247 */ 248 public void reset() { 249 mPreviousRegion.setEmpty(); 250 mPreviousTransformation.clear(); 251 mInitialized = false; 252 mCycleFlip = false; 253 mRepeated = 0; 254 mMore = true; 255 mOneMoreTime = true; 256 } 257 258 /** 259 * Whether or not the animation has been initialized. 260 * 261 * @return Has this animation been initialized. 262 * @see #initialize(int, int, int, int) 263 */ 264 public boolean isInitialized() { 265 return mInitialized; 266 } 267 268 /** 269 * Initialize this animation with the dimensions of the object being 270 * animated as well as the objects parents. (This is to support animation 271 * sizes being specifed relative to these dimensions.) 272 * 273 * <p>Objects that interpret a Animations should call this method when 274 * the sizes of the object being animated and its parent are known, and 275 * before calling {@link #getTransformation}. 276 * 277 * 278 * @param width Width of the object being animated 279 * @param height Height of the object being animated 280 * @param parentWidth Width of the animated object's parent 281 * @param parentHeight Height of the animated object's parent 282 */ 283 public void initialize(int width, int height, int parentWidth, int parentHeight) { 284 reset(); 285 mInitialized = true; 286 } 287 288 /** 289 * Sets the acceleration curve for this animation. The interpolator is loaded as 290 * a resource from the specified context. 291 * 292 * @param context The application environment 293 * @param resID The resource identifier of the interpolator to load 294 * @attr ref android.R.styleable#Animation_interpolator 295 */ 296 public void setInterpolator(Context context, int resID) { 297 setInterpolator(AnimationUtils.loadInterpolator(context, resID)); 298 } 299 300 /** 301 * Sets the acceleration curve for this animation. Defaults to a linear 302 * interpolation. 303 * 304 * @param i The interpolator which defines the acceleration curve 305 * @attr ref android.R.styleable#Animation_interpolator 306 */ 307 public void setInterpolator(Interpolator i) { 308 mInterpolator = i; 309 } 310 311 /** 312 * When this animation should start relative to the start time. This is most 313 * useful when composing complex animations using an {@link AnimationSet } 314 * where some of the animations components start at different times. 315 * 316 * @param startOffset When this Animation should start, in milliseconds from 317 * the start time of the root AnimationSet. 318 * @attr ref android.R.styleable#Animation_startOffset 319 */ 320 public void setStartOffset(long startOffset) { 321 mStartOffset = startOffset; 322 } 323 324 /** 325 * How long this animation should last. The duration cannot be negative. 326 * 327 * @param durationMillis Duration in milliseconds 328 * 329 * @throws java.lang.IllegalArgumentException if the duration is < 0 330 * 331 * @attr ref android.R.styleable#Animation_duration 332 */ 333 public void setDuration(long durationMillis) { 334 if (durationMillis < 0) { 335 throw new IllegalArgumentException("Animation duration cannot be negative"); 336 } 337 mDuration = durationMillis; 338 } 339 340 /** 341 * Ensure that the duration that this animation will run is not longer 342 * than <var>durationMillis</var>. In addition to adjusting the duration 343 * itself, this ensures that the repeat count also will not make it run 344 * longer than the given time. 345 * 346 * @param durationMillis The maximum duration the animation is allowed 347 * to run. 348 */ 349 public void restrictDuration(long durationMillis) { 350 // If we start after the duration, then we just won't run. 351 if (mStartOffset > durationMillis) { 352 mStartOffset = durationMillis; 353 mDuration = 0; 354 mRepeatCount = 0; 355 return; 356 } 357 358 long dur = mDuration + mStartOffset; 359 if (dur > durationMillis) { 360 mDuration = durationMillis-mStartOffset; 361 dur = durationMillis; 362 } 363 // If the duration is 0 or less, then we won't run. 364 if (mDuration <= 0) { 365 mDuration = 0; 366 mRepeatCount = 0; 367 return; 368 } 369 // Reduce the number of repeats to keep below the maximum duration. 370 // The comparison between mRepeatCount and duration is to catch 371 // overflows after multiplying them. 372 if (mRepeatCount < 0 || mRepeatCount > durationMillis 373 || (dur*mRepeatCount) > durationMillis) { 374 // Figure out how many times to do the animation. Subtract 1 since 375 // repeat count is the number of times to repeat so 0 runs once. 376 mRepeatCount = (int)(durationMillis/dur) - 1; 377 if (mRepeatCount < 0) { 378 mRepeatCount = 0; 379 } 380 } 381 } 382 383 /** 384 * How much to scale the duration by. 385 * 386 * @param scale The amount to scale the duration. 387 */ 388 public void scaleCurrentDuration(float scale) { 389 mDuration = (long) (mDuration * scale); 390 } 391 392 /** 393 * When this animation should start. When the start time is set to 394 * {@link #START_ON_FIRST_FRAME}, the animation will start the first time 395 * {@link #getTransformation(long, Transformation)} is invoked. The time passed 396 * to this method should be obtained by calling 397 * {@link AnimationUtils#currentAnimationTimeMillis()} instead of 398 * {@link System#currentTimeMillis()}. 399 * 400 * @param startTimeMillis the start time in milliseconds 401 */ 402 public void setStartTime(long startTimeMillis) { 403 mStartTime = startTimeMillis; 404 mStarted = mEnded = false; 405 mCycleFlip = false; 406 mRepeated = 0; 407 mMore = true; 408 } 409 410 /** 411 * Convenience method to start the animation the first time 412 * {@link #getTransformation(long, Transformation)} is invoked. 413 */ 414 public void start() { 415 setStartTime(-1); 416 } 417 418 /** 419 * Convenience method to start the animation at the current time in 420 * milliseconds. 421 */ 422 public void startNow() { 423 setStartTime(AnimationUtils.currentAnimationTimeMillis()); 424 } 425 426 /** 427 * Defines what this animation should do when it reaches the end. This 428 * setting is applied only when the repeat count is either greater than 429 * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}. 430 * 431 * @param repeatMode {@link #RESTART} or {@link #REVERSE} 432 * @attr ref android.R.styleable#Animation_repeatMode 433 */ 434 public void setRepeatMode(int repeatMode) { 435 mRepeatMode = repeatMode; 436 } 437 438 /** 439 * Sets how many times the animation should be repeated. If the repeat 440 * count is 0, the animation is never repeated. If the repeat count is 441 * greater than 0 or {@link #INFINITE}, the repeat mode will be taken 442 * into account. The repeat count is 0 by default. 443 * 444 * @param repeatCount the number of times the animation should be repeated 445 * @attr ref android.R.styleable#Animation_repeatCount 446 */ 447 public void setRepeatCount(int repeatCount) { 448 if (repeatCount < 0) { 449 repeatCount = INFINITE; 450 } 451 mRepeatCount = repeatCount; 452 } 453 454 /** 455 * If fillEnabled is true, this animation will apply fillBefore and fillAfter. 456 * 457 * @return true if the animation will take fillBefore and fillAfter into account 458 * @attr ref android.R.styleable#Animation_fillEnabled 459 */ 460 public boolean isFillEnabled() { 461 return mFillEnabled; 462 } 463 464 /** 465 * If fillEnabled is true, the animation will apply the value of fillBefore and 466 * fillAfter. Otherwise, fillBefore and fillAfter are ignored and the animation 467 * transformation is always applied. 468 * 469 * @param fillEnabled true if the animation should take fillBefore and fillAfter into account 470 * @attr ref android.R.styleable#Animation_fillEnabled 471 * 472 * @see #setFillBefore(boolean) 473 * @see #setFillAfter(boolean) 474 */ 475 public void setFillEnabled(boolean fillEnabled) { 476 mFillEnabled = fillEnabled; 477 } 478 479 /** 480 * If fillBefore is true, this animation will apply its transformation 481 * before the start time of the animation. Defaults to true if not set. 482 * Note that this applies when using an {@link 483 * android.view.animation.AnimationSet AnimationSet} to chain 484 * animations. The transformation is not applied before the AnimationSet 485 * itself starts. 486 * 487 * @param fillBefore true if the animation should apply its transformation before it starts 488 * @attr ref android.R.styleable#Animation_fillBefore 489 * 490 * @see #setFillEnabled(boolean) 491 */ 492 public void setFillBefore(boolean fillBefore) { 493 mFillBefore = fillBefore; 494 } 495 496 /** 497 * If fillAfter is true, the transformation that this animation performed 498 * will persist when it is finished. Defaults to false if not set. 499 * Note that this applies when using an {@link 500 * android.view.animation.AnimationSet AnimationSet} to chain 501 * animations. The transformation is not applied before the AnimationSet 502 * itself starts. 503 * 504 * @param fillAfter true if the animation should apply its transformation after it ends 505 * @attr ref android.R.styleable#Animation_fillAfter 506 * 507 * @see #setFillEnabled(boolean) 508 */ 509 public void setFillAfter(boolean fillAfter) { 510 mFillAfter = fillAfter; 511 } 512 513 /** 514 * Set the Z ordering mode to use while running the animation. 515 * 516 * @param zAdjustment The desired mode, one of {@link #ZORDER_NORMAL}, 517 * {@link #ZORDER_TOP}, or {@link #ZORDER_BOTTOM}. 518 * @attr ref android.R.styleable#Animation_zAdjustment 519 */ 520 public void setZAdjustment(int zAdjustment) { 521 mZAdjustment = zAdjustment; 522 } 523 524 /** 525 * If detachWallpaper is true, and this is a window animation of a window 526 * that has a wallpaper background, then the window will be detached from 527 * the wallpaper while it runs. That is, the animation will only be applied 528 * to the window, and the wallpaper behind it will remain static. 529 * 530 * @param detachWallpaper true if the wallpaper should be detached from the animation 531 * @attr ref android.R.styleable#Animation_detachWallpaper 532 */ 533 public void setDetachWallpaper(boolean detachWallpaper) { 534 mDetachWallpaper = detachWallpaper; 535 } 536 537 /** 538 * Gets the acceleration curve type for this animation. 539 * 540 * @return the {@link Interpolator} associated to this animation 541 * @attr ref android.R.styleable#Animation_interpolator 542 */ 543 public Interpolator getInterpolator() { 544 return mInterpolator; 545 } 546 547 /** 548 * When this animation should start. If the animation has not startet yet, 549 * this method might return {@link #START_ON_FIRST_FRAME}. 550 * 551 * @return the time in milliseconds when the animation should start or 552 * {@link #START_ON_FIRST_FRAME} 553 */ 554 public long getStartTime() { 555 return mStartTime; 556 } 557 558 /** 559 * How long this animation should last 560 * 561 * @return the duration in milliseconds of the animation 562 * @attr ref android.R.styleable#Animation_duration 563 */ 564 public long getDuration() { 565 return mDuration; 566 } 567 568 /** 569 * When this animation should start, relative to StartTime 570 * 571 * @return the start offset in milliseconds 572 * @attr ref android.R.styleable#Animation_startOffset 573 */ 574 public long getStartOffset() { 575 return mStartOffset; 576 } 577 578 /** 579 * Defines what this animation should do when it reaches the end. 580 * 581 * @return either one of {@link #REVERSE} or {@link #RESTART} 582 * @attr ref android.R.styleable#Animation_repeatMode 583 */ 584 public int getRepeatMode() { 585 return mRepeatMode; 586 } 587 588 /** 589 * Defines how many times the animation should repeat. The default value 590 * is 0. 591 * 592 * @return the number of times the animation should repeat, or {@link #INFINITE} 593 * @attr ref android.R.styleable#Animation_repeatCount 594 */ 595 public int getRepeatCount() { 596 return mRepeatCount; 597 } 598 599 /** 600 * If fillBefore is true, this animation will apply its transformation 601 * before the start time of the animation. 602 * 603 * @return true if the animation applies its transformation before it starts 604 * @attr ref android.R.styleable#Animation_fillBefore 605 */ 606 public boolean getFillBefore() { 607 return mFillBefore; 608 } 609 610 /** 611 * If fillAfter is true, this animation will apply its transformation 612 * after the end time of the animation. 613 * 614 * @return true if the animation applies its transformation after it ends 615 * @attr ref android.R.styleable#Animation_fillAfter 616 */ 617 public boolean getFillAfter() { 618 return mFillAfter; 619 } 620 621 /** 622 * Returns the Z ordering mode to use while running the animation as 623 * previously set by {@link #setZAdjustment}. 624 * 625 * @return Returns one of {@link #ZORDER_NORMAL}, 626 * {@link #ZORDER_TOP}, or {@link #ZORDER_BOTTOM}. 627 * @attr ref android.R.styleable#Animation_zAdjustment 628 */ 629 public int getZAdjustment() { 630 return mZAdjustment; 631 } 632 633 /** 634 * Return value of {@link #setDetachWallpaper(boolean)}. 635 * @attr ref android.R.styleable#Animation_detachWallpaper 636 */ 637 public boolean getDetachWallpaper() { 638 return mDetachWallpaper; 639 } 640 641 /** 642 * <p>Indicates whether or not this animation will affect the transformation 643 * matrix. For instance, a fade animation will not affect the matrix whereas 644 * a scale animation will.</p> 645 * 646 * @return true if this animation will change the transformation matrix 647 */ 648 public boolean willChangeTransformationMatrix() { 649 // assume we will change the matrix 650 return true; 651 } 652 653 /** 654 * <p>Indicates whether or not this animation will affect the bounds of the 655 * animated view. For instance, a fade animation will not affect the bounds 656 * whereas a 200% scale animation will.</p> 657 * 658 * @return true if this animation will change the view's bounds 659 */ 660 public boolean willChangeBounds() { 661 // assume we will change the bounds 662 return true; 663 } 664 665 /** 666 * <p>Binds an animation listener to this animation. The animation listener 667 * is notified of animation events such as the end of the animation or the 668 * repetition of the animation.</p> 669 * 670 * @param listener the animation listener to be notified 671 */ 672 public void setAnimationListener(AnimationListener listener) { 673 mListener = listener; 674 } 675 676 /** 677 * Gurantees that this animation has an interpolator. Will use 678 * a AccelerateDecelerateInterpolator is nothing else was specified. 679 */ 680 protected void ensureInterpolator() { 681 if (mInterpolator == null) { 682 mInterpolator = new AccelerateDecelerateInterpolator(); 683 } 684 } 685 686 /** 687 * Compute a hint at how long the entire animation may last, in milliseconds. 688 * Animations can be written to cause themselves to run for a different 689 * duration than what is computed here, but generally this should be 690 * accurate. 691 */ 692 public long computeDurationHint() { 693 return (getStartOffset() + getDuration()) * (getRepeatCount() + 1); 694 } 695 696 /** 697 * Gets the transformation to apply at a specified point in time. Implementations of this 698 * method should always replace the specified Transformation or document they are doing 699 * otherwise. 700 * 701 * @param currentTime Where we are in the animation. This is wall clock time. 702 * @param outTransformation A tranformation object that is provided by the 703 * caller and will be filled in by the animation. 704 * @return True if the animation is still running 705 */ 706 public boolean getTransformation(long currentTime, Transformation outTransformation) { 707 if (mStartTime == -1) { 708 mStartTime = currentTime; 709 } 710 711 final long startOffset = getStartOffset(); 712 final long duration = mDuration; 713 float normalizedTime; 714 if (duration != 0) { 715 normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) / 716 (float) duration; 717 } else { 718 // time is a step-change with a zero duration 719 normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f; 720 } 721 722 final boolean expired = normalizedTime >= 1.0f; 723 mMore = !expired; 724 725 if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f); 726 727 if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) { 728 if (!mStarted) { 729 if (mListener != null) { 730 mListener.onAnimationStart(this); 731 } 732 mStarted = true; 733 } 734 735 if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f); 736 737 if (mCycleFlip) { 738 normalizedTime = 1.0f - normalizedTime; 739 } 740 741 final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime); 742 applyTransformation(interpolatedTime, outTransformation); 743 } 744 745 if (expired) { 746 if (mRepeatCount == mRepeated) { 747 if (!mEnded) { 748 if (mListener != null) { 749 mListener.onAnimationEnd(this); 750 } 751 mEnded = true; 752 } 753 } else { 754 if (mRepeatCount > 0) { 755 mRepeated++; 756 } 757 758 if (mRepeatMode == REVERSE) { 759 mCycleFlip = !mCycleFlip; 760 } 761 762 mStartTime = -1; 763 mMore = true; 764 765 if (mListener != null) { 766 mListener.onAnimationRepeat(this); 767 } 768 } 769 } 770 771 if (!mMore && mOneMoreTime) { 772 mOneMoreTime = false; 773 return true; 774 } 775 776 return mMore; 777 } 778 779 /** 780 * <p>Indicates whether this animation has started or not.</p> 781 * 782 * @return true if the animation has started, false otherwise 783 */ 784 public boolean hasStarted() { 785 return mStarted; 786 } 787 788 /** 789 * <p>Indicates whether this animation has ended or not.</p> 790 * 791 * @return true if the animation has ended, false otherwise 792 */ 793 public boolean hasEnded() { 794 return mEnded; 795 } 796 797 /** 798 * Helper for getTransformation. Subclasses should implement this to apply 799 * their transforms given an interpolation value. Implementations of this 800 * method should always replace the specified Transformation or document 801 * they are doing otherwise. 802 * 803 * @param interpolatedTime The value of the normalized time (0.0 to 1.0) 804 * after it has been run through the interpolation function. 805 * @param t The Transofrmation object to fill in with the current 806 * transforms. 807 */ 808 protected void applyTransformation(float interpolatedTime, Transformation t) { 809 } 810 811 /** 812 * Convert the information in the description of a size to an actual 813 * dimension 814 * 815 * @param type One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or 816 * Animation.RELATIVE_TO_PARENT. 817 * @param value The dimension associated with the type parameter 818 * @param size The size of the object being animated 819 * @param parentSize The size of the parent of the object being animated 820 * @return The dimension to use for the animation 821 */ 822 protected float resolveSize(int type, float value, int size, int parentSize) { 823 switch (type) { 824 case ABSOLUTE: 825 return value; 826 case RELATIVE_TO_SELF: 827 return size * value; 828 case RELATIVE_TO_PARENT: 829 return parentSize * value; 830 default: 831 return value; 832 } 833 } 834 835 /** 836 * @param left 837 * @param top 838 * @param right 839 * @param bottom 840 * @param invalidate 841 * @param transformation 842 * 843 * @hide 844 */ 845 public void getInvalidateRegion(int left, int top, int right, int bottom, 846 RectF invalidate, Transformation transformation) { 847 848 final RectF tempRegion = mRegion; 849 final RectF previousRegion = mPreviousRegion; 850 851 invalidate.set(left, top, right, bottom); 852 transformation.getMatrix().mapRect(invalidate); 853 // Enlarge the invalidate region to account for rounding errors 854 invalidate.inset(-1.0f, -1.0f); 855 tempRegion.set(invalidate); 856 invalidate.union(previousRegion); 857 858 previousRegion.set(tempRegion); 859 860 final Transformation tempTransformation = mTransformation; 861 final Transformation previousTransformation = mPreviousTransformation; 862 863 tempTransformation.set(transformation); 864 transformation.set(previousTransformation); 865 previousTransformation.set(tempTransformation); 866 } 867 868 /** 869 * @param left 870 * @param top 871 * @param right 872 * @param bottom 873 * 874 * @hide 875 */ 876 public void initializeInvalidateRegion(int left, int top, int right, int bottom) { 877 final RectF region = mPreviousRegion; 878 region.set(left, top, right, bottom); 879 // Enlarge the invalidate region to account for rounding errors 880 region.inset(-1.0f, -1.0f); 881 if (mFillBefore) { 882 final Transformation previousTransformation = mPreviousTransformation; 883 applyTransformation(mInterpolator.getInterpolation(0.0f), previousTransformation); 884 } 885 } 886 887 /** 888 * Utility class to parse a string description of a size. 889 */ 890 protected static class Description { 891 /** 892 * One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or 893 * Animation.RELATIVE_TO_PARENT. 894 */ 895 public int type; 896 897 /** 898 * The absolute or relative dimension for this Description. 899 */ 900 public float value; 901 902 /** 903 * Size descriptions can appear inthree forms: 904 * <ol> 905 * <li>An absolute size. This is represented by a number.</li> 906 * <li>A size relative to the size of the object being animated. This 907 * is represented by a number followed by "%".</li> * 908 * <li>A size relative to the size of the parent of object being 909 * animated. This is represented by a number followed by "%p".</li> 910 * </ol> 911 * @param value The typed value to parse 912 * @return The parsed version of the description 913 */ 914 static Description parseValue(TypedValue value) { 915 Description d = new Description(); 916 if (value == null) { 917 d.type = ABSOLUTE; 918 d.value = 0; 919 } else { 920 if (value.type == TypedValue.TYPE_FRACTION) { 921 d.type = (value.data & TypedValue.COMPLEX_UNIT_MASK) == 922 TypedValue.COMPLEX_UNIT_FRACTION_PARENT ? 923 RELATIVE_TO_PARENT : RELATIVE_TO_SELF; 924 d.value = TypedValue.complexToFloat(value.data); 925 return d; 926 } else if (value.type == TypedValue.TYPE_FLOAT) { 927 d.type = ABSOLUTE; 928 d.value = value.getFloat(); 929 return d; 930 } else if (value.type >= TypedValue.TYPE_FIRST_INT && 931 value.type <= TypedValue.TYPE_LAST_INT) { 932 d.type = ABSOLUTE; 933 d.value = value.data; 934 return d; 935 } 936 } 937 938 d.type = ABSOLUTE; 939 d.value = 0.0f; 940 941 return d; 942 } 943 } 944 945 /** 946 * <p>An animation listener receives notifications from an animation. 947 * Notifications indicate animation related events, such as the end or the 948 * repetition of the animation.</p> 949 */ 950 public static interface AnimationListener { 951 /** 952 * <p>Notifies the start of the animation.</p> 953 * 954 * @param animation The started animation. 955 */ 956 void onAnimationStart(Animation animation); 957 958 /** 959 * <p>Notifies the end of the animation. This callback is not invoked 960 * for animations with repeat count set to INFINITE.</p> 961 * 962 * @param animation The animation which reached its end. 963 */ 964 void onAnimationEnd(Animation animation); 965 966 /** 967 * <p>Notifies the repetition of the animation.</p> 968 * 969 * @param animation The animation which was repeated. 970 */ 971 void onAnimationRepeat(Animation animation); 972 } 973} 974