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