PageRenderTime 48ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/src/backports/animation/ValueAnimator.java

https://bitbucket.org/fredgrott/gwsdroidfeel
Java | 1280 lines | 589 code | 101 blank | 590 comment | 149 complexity | af10734e8630b8863df1920e07cd071d MD5 | raw file

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file