/core/java/android/view/ViewPropertyAnimator.java

https://bitbucket.org/seandroid/frameworks-base · Java · 1195 lines · 569 code · 79 blank · 547 comment · 111 complexity · 26585bad578a28e9fd2b51c754ca8c8c MD5 · raw file

  1. /*
  2. * Copyright (C) 2011 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 android.view;
  17. import android.animation.Animator;
  18. import android.animation.ValueAnimator;
  19. import android.animation.TimeInterpolator;
  20. import java.util.ArrayList;
  21. import java.util.HashMap;
  22. import java.util.Set;
  23. /**
  24. * This class enables automatic and optimized animation of select properties on View objects.
  25. * If only one or two properties on a View object are being animated, then using an
  26. * {@link android.animation.ObjectAnimator} is fine; the property setters called by ObjectAnimator
  27. * are well equipped to do the right thing to set the property and invalidate the view
  28. * appropriately. But if several properties are animated simultaneously, or if you just want a
  29. * more convenient syntax to animate a specific property, then ViewPropertyAnimator might be
  30. * more well-suited to the task.
  31. *
  32. * <p>This class may provide better performance for several simultaneous animations, because
  33. * it will optimize invalidate calls to take place only once for several properties instead of each
  34. * animated property independently causing its own invalidation. Also, the syntax of using this
  35. * class could be easier to use because the caller need only tell the View object which
  36. * property to animate, and the value to animate either to or by, and this class handles the
  37. * details of configuring the underlying Animator class and starting it.</p>
  38. *
  39. * <p>This class is not constructed by the caller, but rather by the View whose properties
  40. * it will animate. Calls to {@link android.view.View#animate()} will return a reference
  41. * to the appropriate ViewPropertyAnimator object for that View.</p>
  42. *
  43. */
  44. public class ViewPropertyAnimator {
  45. /**
  46. * The View whose properties are being animated by this class. This is set at
  47. * construction time.
  48. */
  49. final View mView;
  50. /**
  51. * The duration of the underlying Animator object. By default, we don't set the duration
  52. * on the Animator and just use its default duration. If the duration is ever set on this
  53. * Animator, then we use the duration that it was set to.
  54. */
  55. private long mDuration;
  56. /**
  57. * A flag indicating whether the duration has been set on this object. If not, we don't set
  58. * the duration on the underlying Animator, but instead just use its default duration.
  59. */
  60. private boolean mDurationSet = false;
  61. /**
  62. * The startDelay of the underlying Animator object. By default, we don't set the startDelay
  63. * on the Animator and just use its default startDelay. If the startDelay is ever set on this
  64. * Animator, then we use the startDelay that it was set to.
  65. */
  66. private long mStartDelay = 0;
  67. /**
  68. * A flag indicating whether the startDelay has been set on this object. If not, we don't set
  69. * the startDelay on the underlying Animator, but instead just use its default startDelay.
  70. */
  71. private boolean mStartDelaySet = false;
  72. /**
  73. * The interpolator of the underlying Animator object. By default, we don't set the interpolator
  74. * on the Animator and just use its default interpolator. If the interpolator is ever set on
  75. * this Animator, then we use the interpolator that it was set to.
  76. */
  77. private TimeInterpolator mInterpolator;
  78. /**
  79. * A flag indicating whether the interpolator has been set on this object. If not, we don't set
  80. * the interpolator on the underlying Animator, but instead just use its default interpolator.
  81. */
  82. private boolean mInterpolatorSet = false;
  83. /**
  84. * Listener for the lifecycle events of the underlying ValueAnimator object.
  85. */
  86. private Animator.AnimatorListener mListener = null;
  87. /**
  88. * Listener for the update events of the underlying ValueAnimator object.
  89. */
  90. private ValueAnimator.AnimatorUpdateListener mUpdateListener = null;
  91. /**
  92. * A lazily-created ValueAnimator used in order to get some default animator properties
  93. * (duration, start delay, interpolator, etc.).
  94. */
  95. private ValueAnimator mTempValueAnimator;
  96. /**
  97. * A RenderThread-driven backend that may intercept startAnimation
  98. */
  99. private ViewPropertyAnimatorRT mRTBackend;
  100. /**
  101. * This listener is the mechanism by which the underlying Animator causes changes to the
  102. * properties currently being animated, as well as the cleanup after an animation is
  103. * complete.
  104. */
  105. private AnimatorEventListener mAnimatorEventListener = new AnimatorEventListener();
  106. /**
  107. * This list holds the properties that have been asked to animate. We allow the caller to
  108. * request several animations prior to actually starting the underlying animator. This
  109. * enables us to run one single animator to handle several properties in parallel. Each
  110. * property is tossed onto the pending list until the animation actually starts (which is
  111. * done by posting it onto mView), at which time the pending list is cleared and the properties
  112. * on that list are added to the list of properties associated with that animator.
  113. */
  114. ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();
  115. private Runnable mPendingSetupAction;
  116. private Runnable mPendingCleanupAction;
  117. private Runnable mPendingOnStartAction;
  118. private Runnable mPendingOnEndAction;
  119. /**
  120. * Constants used to associate a property being requested and the mechanism used to set
  121. * the property (this class calls directly into View to set the properties in question).
  122. */
  123. static final int NONE = 0x0000;
  124. static final int TRANSLATION_X = 0x0001;
  125. static final int TRANSLATION_Y = 0x0002;
  126. static final int TRANSLATION_Z = 0x0004;
  127. static final int SCALE_X = 0x0008;
  128. static final int SCALE_Y = 0x0010;
  129. static final int ROTATION = 0x0020;
  130. static final int ROTATION_X = 0x0040;
  131. static final int ROTATION_Y = 0x0080;
  132. static final int X = 0x0100;
  133. static final int Y = 0x0200;
  134. static final int Z = 0x0400;
  135. static final int ALPHA = 0x0800;
  136. private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | TRANSLATION_Z |
  137. SCALE_X | SCALE_Y | ROTATION | ROTATION_X | ROTATION_Y | X | Y | Z;
  138. /**
  139. * The mechanism by which the user can request several properties that are then animated
  140. * together works by posting this Runnable to start the underlying Animator. Every time
  141. * a property animation is requested, we cancel any previous postings of the Runnable
  142. * and re-post it. This means that we will only ever run the Runnable (and thus start the
  143. * underlying animator) after the caller is done setting the properties that should be
  144. * animated together.
  145. */
  146. private Runnable mAnimationStarter = new Runnable() {
  147. @Override
  148. public void run() {
  149. startAnimation();
  150. }
  151. };
  152. /**
  153. * This class holds information about the overall animation being run on the set of
  154. * properties. The mask describes which properties are being animated and the
  155. * values holder is the list of all property/value objects.
  156. */
  157. private static class PropertyBundle {
  158. int mPropertyMask;
  159. ArrayList<NameValuesHolder> mNameValuesHolder;
  160. PropertyBundle(int propertyMask, ArrayList<NameValuesHolder> nameValuesHolder) {
  161. mPropertyMask = propertyMask;
  162. mNameValuesHolder = nameValuesHolder;
  163. }
  164. /**
  165. * Removes the given property from being animated as a part of this
  166. * PropertyBundle. If the property was a part of this bundle, it returns
  167. * true to indicate that it was, in fact, canceled. This is an indication
  168. * to the caller that a cancellation actually occurred.
  169. *
  170. * @param propertyConstant The property whose cancellation is requested.
  171. * @return true if the given property is a part of this bundle and if it
  172. * has therefore been canceled.
  173. */
  174. boolean cancel(int propertyConstant) {
  175. if ((mPropertyMask & propertyConstant) != 0 && mNameValuesHolder != null) {
  176. int count = mNameValuesHolder.size();
  177. for (int i = 0; i < count; ++i) {
  178. NameValuesHolder nameValuesHolder = mNameValuesHolder.get(i);
  179. if (nameValuesHolder.mNameConstant == propertyConstant) {
  180. mNameValuesHolder.remove(i);
  181. mPropertyMask &= ~propertyConstant;
  182. return true;
  183. }
  184. }
  185. }
  186. return false;
  187. }
  188. }
  189. /**
  190. * This list tracks the list of properties being animated by any particular animator.
  191. * In most situations, there would only ever be one animator running at a time. But it is
  192. * possible to request some properties to animate together, then while those properties
  193. * are animating, to request some other properties to animate together. The way that
  194. * works is by having this map associate the group of properties being animated with the
  195. * animator handling the animation. On every update event for an Animator, we ask the
  196. * map for the associated properties and set them accordingly.
  197. */
  198. private HashMap<Animator, PropertyBundle> mAnimatorMap =
  199. new HashMap<Animator, PropertyBundle>();
  200. private HashMap<Animator, Runnable> mAnimatorSetupMap;
  201. private HashMap<Animator, Runnable> mAnimatorCleanupMap;
  202. private HashMap<Animator, Runnable> mAnimatorOnStartMap;
  203. private HashMap<Animator, Runnable> mAnimatorOnEndMap;
  204. /**
  205. * This is the information we need to set each property during the animation.
  206. * mNameConstant is used to set the appropriate field in View, and the from/delta
  207. * values are used to calculate the animated value for a given animation fraction
  208. * during the animation.
  209. */
  210. static class NameValuesHolder {
  211. int mNameConstant;
  212. float mFromValue;
  213. float mDeltaValue;
  214. NameValuesHolder(int nameConstant, float fromValue, float deltaValue) {
  215. mNameConstant = nameConstant;
  216. mFromValue = fromValue;
  217. mDeltaValue = deltaValue;
  218. }
  219. }
  220. /**
  221. * Constructor, called by View. This is private by design, as the user should only
  222. * get a ViewPropertyAnimator by calling View.animate().
  223. *
  224. * @param view The View associated with this ViewPropertyAnimator
  225. */
  226. ViewPropertyAnimator(View view) {
  227. mView = view;
  228. view.ensureTransformationInfo();
  229. }
  230. /**
  231. * Sets the duration for the underlying animator that animates the requested properties.
  232. * By default, the animator uses the default value for ValueAnimator. Calling this method
  233. * will cause the declared value to be used instead.
  234. * @param duration The length of ensuing property animations, in milliseconds. The value
  235. * cannot be negative.
  236. * @return This object, allowing calls to methods in this class to be chained.
  237. */
  238. public ViewPropertyAnimator setDuration(long duration) {
  239. if (duration < 0) {
  240. throw new IllegalArgumentException("Animators cannot have negative duration: " +
  241. duration);
  242. }
  243. mDurationSet = true;
  244. mDuration = duration;
  245. return this;
  246. }
  247. /**
  248. * Returns the current duration of property animations. If the duration was set on this
  249. * object, that value is returned. Otherwise, the default value of the underlying Animator
  250. * is returned.
  251. *
  252. * @see #setDuration(long)
  253. * @return The duration of animations, in milliseconds.
  254. */
  255. public long getDuration() {
  256. if (mDurationSet) {
  257. return mDuration;
  258. } else {
  259. // Just return the default from ValueAnimator, since that's what we'd get if
  260. // the value has not been set otherwise
  261. if (mTempValueAnimator == null) {
  262. mTempValueAnimator = new ValueAnimator();
  263. }
  264. return mTempValueAnimator.getDuration();
  265. }
  266. }
  267. /**
  268. * Returns the current startDelay of property animations. If the startDelay was set on this
  269. * object, that value is returned. Otherwise, the default value of the underlying Animator
  270. * is returned.
  271. *
  272. * @see #setStartDelay(long)
  273. * @return The startDelay of animations, in milliseconds.
  274. */
  275. public long getStartDelay() {
  276. if (mStartDelaySet) {
  277. return mStartDelay;
  278. } else {
  279. // Just return the default from ValueAnimator (0), since that's what we'd get if
  280. // the value has not been set otherwise
  281. return 0;
  282. }
  283. }
  284. /**
  285. * Sets the startDelay for the underlying animator that animates the requested properties.
  286. * By default, the animator uses the default value for ValueAnimator. Calling this method
  287. * will cause the declared value to be used instead.
  288. * @param startDelay The delay of ensuing property animations, in milliseconds. The value
  289. * cannot be negative.
  290. * @return This object, allowing calls to methods in this class to be chained.
  291. */
  292. public ViewPropertyAnimator setStartDelay(long startDelay) {
  293. if (startDelay < 0) {
  294. throw new IllegalArgumentException("Animators cannot have negative start " +
  295. "delay: " + startDelay);
  296. }
  297. mStartDelaySet = true;
  298. mStartDelay = startDelay;
  299. return this;
  300. }
  301. /**
  302. * Sets the interpolator for the underlying animator that animates the requested properties.
  303. * By default, the animator uses the default interpolator for ValueAnimator. Calling this method
  304. * will cause the declared object to be used instead.
  305. *
  306. * @param interpolator The TimeInterpolator to be used for ensuing property animations. A value
  307. * of <code>null</code> will result in linear interpolation.
  308. * @return This object, allowing calls to methods in this class to be chained.
  309. */
  310. public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) {
  311. mInterpolatorSet = true;
  312. mInterpolator = interpolator;
  313. return this;
  314. }
  315. /**
  316. * Returns the timing interpolator that this animation uses.
  317. *
  318. * @return The timing interpolator for this animation.
  319. */
  320. public TimeInterpolator getInterpolator() {
  321. if (mInterpolatorSet) {
  322. return mInterpolator;
  323. } else {
  324. // Just return the default from ValueAnimator, since that's what we'd get if
  325. // the value has not been set otherwise
  326. if (mTempValueAnimator == null) {
  327. mTempValueAnimator = new ValueAnimator();
  328. }
  329. return mTempValueAnimator.getInterpolator();
  330. }
  331. }
  332. /**
  333. * Sets a listener for events in the underlying Animators that run the property
  334. * animations.
  335. *
  336. * @see Animator.AnimatorListener
  337. *
  338. * @param listener The listener to be called with AnimatorListener events. A value of
  339. * <code>null</code> removes any existing listener.
  340. * @return This object, allowing calls to methods in this class to be chained.
  341. */
  342. public ViewPropertyAnimator setListener(Animator.AnimatorListener listener) {
  343. mListener = listener;
  344. return this;
  345. }
  346. Animator.AnimatorListener getListener() {
  347. return mListener;
  348. }
  349. /**
  350. * Sets a listener for update events in the underlying ValueAnimator that runs
  351. * the property animations. Note that the underlying animator is animating between
  352. * 0 and 1 (these values are then turned into the actual property values internally
  353. * by ViewPropertyAnimator). So the animator cannot give information on the current
  354. * values of the properties being animated by this ViewPropertyAnimator, although
  355. * the view object itself can be queried to get the current values.
  356. *
  357. * @see android.animation.ValueAnimator.AnimatorUpdateListener
  358. *
  359. * @param listener The listener to be called with update events. A value of
  360. * <code>null</code> removes any existing listener.
  361. * @return This object, allowing calls to methods in this class to be chained.
  362. */
  363. public ViewPropertyAnimator setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) {
  364. mUpdateListener = listener;
  365. return this;
  366. }
  367. ValueAnimator.AnimatorUpdateListener getUpdateListener() {
  368. return mUpdateListener;
  369. }
  370. /**
  371. * Starts the currently pending property animations immediately. Calling <code>start()</code>
  372. * is optional because all animations start automatically at the next opportunity. However,
  373. * if the animations are needed to start immediately and synchronously (not at the time when
  374. * the next event is processed by the hierarchy, which is when the animations would begin
  375. * otherwise), then this method can be used.
  376. */
  377. public void start() {
  378. mView.removeCallbacks(mAnimationStarter);
  379. startAnimation();
  380. }
  381. /**
  382. * Cancels all property animations that are currently running or pending.
  383. */
  384. public void cancel() {
  385. if (mAnimatorMap.size() > 0) {
  386. HashMap<Animator, PropertyBundle> mAnimatorMapCopy =
  387. (HashMap<Animator, PropertyBundle>)mAnimatorMap.clone();
  388. Set<Animator> animatorSet = mAnimatorMapCopy.keySet();
  389. for (Animator runningAnim : animatorSet) {
  390. runningAnim.cancel();
  391. }
  392. }
  393. mPendingAnimations.clear();
  394. mPendingSetupAction = null;
  395. mPendingCleanupAction = null;
  396. mPendingOnStartAction = null;
  397. mPendingOnEndAction = null;
  398. mView.removeCallbacks(mAnimationStarter);
  399. if (mRTBackend != null) {
  400. mRTBackend.cancelAll();
  401. }
  402. }
  403. /**
  404. * This method will cause the View's <code>x</code> property to be animated to the
  405. * specified value. Animations already running on the property will be canceled.
  406. *
  407. * @param value The value to be animated to.
  408. * @see View#setX(float)
  409. * @return This object, allowing calls to methods in this class to be chained.
  410. */
  411. public ViewPropertyAnimator x(float value) {
  412. animateProperty(X, value);
  413. return this;
  414. }
  415. /**
  416. * This method will cause the View's <code>x</code> property to be animated by the
  417. * specified value. Animations already running on the property will be canceled.
  418. *
  419. * @param value The amount to be animated by, as an offset from the current value.
  420. * @see View#setX(float)
  421. * @return This object, allowing calls to methods in this class to be chained.
  422. */
  423. public ViewPropertyAnimator xBy(float value) {
  424. animatePropertyBy(X, value);
  425. return this;
  426. }
  427. /**
  428. * This method will cause the View's <code>y</code> property to be animated to the
  429. * specified value. Animations already running on the property will be canceled.
  430. *
  431. * @param value The value to be animated to.
  432. * @see View#setY(float)
  433. * @return This object, allowing calls to methods in this class to be chained.
  434. */
  435. public ViewPropertyAnimator y(float value) {
  436. animateProperty(Y, value);
  437. return this;
  438. }
  439. /**
  440. * This method will cause the View's <code>y</code> property to be animated by the
  441. * specified value. Animations already running on the property will be canceled.
  442. *
  443. * @param value The amount to be animated by, as an offset from the current value.
  444. * @see View#setY(float)
  445. * @return This object, allowing calls to methods in this class to be chained.
  446. */
  447. public ViewPropertyAnimator yBy(float value) {
  448. animatePropertyBy(Y, value);
  449. return this;
  450. }
  451. /**
  452. * This method will cause the View's <code>z</code> property to be animated to the
  453. * specified value. Animations already running on the property will be canceled.
  454. *
  455. * @param value The value to be animated to.
  456. * @see View#setZ(float)
  457. * @return This object, allowing calls to methods in this class to be chained.
  458. */
  459. public ViewPropertyAnimator z(float value) {
  460. animateProperty(Z, value);
  461. return this;
  462. }
  463. /**
  464. * This method will cause the View's <code>z</code> property to be animated by the
  465. * specified value. Animations already running on the property will be canceled.
  466. *
  467. * @param value The amount to be animated by, as an offset from the current value.
  468. * @see View#setZ(float)
  469. * @return This object, allowing calls to methods in this class to be chained.
  470. */
  471. public ViewPropertyAnimator zBy(float value) {
  472. animatePropertyBy(Z, value);
  473. return this;
  474. }
  475. /**
  476. * This method will cause the View's <code>rotation</code> property to be animated to the
  477. * specified value. Animations already running on the property will be canceled.
  478. *
  479. * @param value The value to be animated to.
  480. * @see View#setRotation(float)
  481. * @return This object, allowing calls to methods in this class to be chained.
  482. */
  483. public ViewPropertyAnimator rotation(float value) {
  484. animateProperty(ROTATION, value);
  485. return this;
  486. }
  487. /**
  488. * This method will cause the View's <code>rotation</code> property to be animated by the
  489. * specified value. Animations already running on the property will be canceled.
  490. *
  491. * @param value The amount to be animated by, as an offset from the current value.
  492. * @see View#setRotation(float)
  493. * @return This object, allowing calls to methods in this class to be chained.
  494. */
  495. public ViewPropertyAnimator rotationBy(float value) {
  496. animatePropertyBy(ROTATION, value);
  497. return this;
  498. }
  499. /**
  500. * This method will cause the View's <code>rotationX</code> property to be animated to the
  501. * specified value. Animations already running on the property will be canceled.
  502. *
  503. * @param value The value to be animated to.
  504. * @see View#setRotationX(float)
  505. * @return This object, allowing calls to methods in this class to be chained.
  506. */
  507. public ViewPropertyAnimator rotationX(float value) {
  508. animateProperty(ROTATION_X, value);
  509. return this;
  510. }
  511. /**
  512. * This method will cause the View's <code>rotationX</code> property to be animated by the
  513. * specified value. Animations already running on the property will be canceled.
  514. *
  515. * @param value The amount to be animated by, as an offset from the current value.
  516. * @see View#setRotationX(float)
  517. * @return This object, allowing calls to methods in this class to be chained.
  518. */
  519. public ViewPropertyAnimator rotationXBy(float value) {
  520. animatePropertyBy(ROTATION_X, value);
  521. return this;
  522. }
  523. /**
  524. * This method will cause the View's <code>rotationY</code> property to be animated to the
  525. * specified value. Animations already running on the property will be canceled.
  526. *
  527. * @param value The value to be animated to.
  528. * @see View#setRotationY(float)
  529. * @return This object, allowing calls to methods in this class to be chained.
  530. */
  531. public ViewPropertyAnimator rotationY(float value) {
  532. animateProperty(ROTATION_Y, value);
  533. return this;
  534. }
  535. /**
  536. * This method will cause the View's <code>rotationY</code> property to be animated by the
  537. * specified value. Animations already running on the property will be canceled.
  538. *
  539. * @param value The amount to be animated by, as an offset from the current value.
  540. * @see View#setRotationY(float)
  541. * @return This object, allowing calls to methods in this class to be chained.
  542. */
  543. public ViewPropertyAnimator rotationYBy(float value) {
  544. animatePropertyBy(ROTATION_Y, value);
  545. return this;
  546. }
  547. /**
  548. * This method will cause the View's <code>translationX</code> property to be animated to the
  549. * specified value. Animations already running on the property will be canceled.
  550. *
  551. * @param value The value to be animated to.
  552. * @see View#setTranslationX(float)
  553. * @return This object, allowing calls to methods in this class to be chained.
  554. */
  555. public ViewPropertyAnimator translationX(float value) {
  556. animateProperty(TRANSLATION_X, value);
  557. return this;
  558. }
  559. /**
  560. * This method will cause the View's <code>translationX</code> property to be animated by the
  561. * specified value. Animations already running on the property will be canceled.
  562. *
  563. * @param value The amount to be animated by, as an offset from the current value.
  564. * @see View#setTranslationX(float)
  565. * @return This object, allowing calls to methods in this class to be chained.
  566. */
  567. public ViewPropertyAnimator translationXBy(float value) {
  568. animatePropertyBy(TRANSLATION_X, value);
  569. return this;
  570. }
  571. /**
  572. * This method will cause the View's <code>translationY</code> property to be animated to the
  573. * specified value. Animations already running on the property will be canceled.
  574. *
  575. * @param value The value to be animated to.
  576. * @see View#setTranslationY(float)
  577. * @return This object, allowing calls to methods in this class to be chained.
  578. */
  579. public ViewPropertyAnimator translationY(float value) {
  580. animateProperty(TRANSLATION_Y, value);
  581. return this;
  582. }
  583. /**
  584. * This method will cause the View's <code>translationY</code> property to be animated by the
  585. * specified value. Animations already running on the property will be canceled.
  586. *
  587. * @param value The amount to be animated by, as an offset from the current value.
  588. * @see View#setTranslationY(float)
  589. * @return This object, allowing calls to methods in this class to be chained.
  590. */
  591. public ViewPropertyAnimator translationYBy(float value) {
  592. animatePropertyBy(TRANSLATION_Y, value);
  593. return this;
  594. }
  595. /**
  596. * This method will cause the View's <code>translationZ</code> property to be animated to the
  597. * specified value. Animations already running on the property will be canceled.
  598. *
  599. * @param value The value to be animated to.
  600. * @see View#setTranslationZ(float)
  601. * @return This object, allowing calls to methods in this class to be chained.
  602. */
  603. public ViewPropertyAnimator translationZ(float value) {
  604. animateProperty(TRANSLATION_Z, value);
  605. return this;
  606. }
  607. /**
  608. * This method will cause the View's <code>translationZ</code> property to be animated by the
  609. * specified value. Animations already running on the property will be canceled.
  610. *
  611. * @param value The amount to be animated by, as an offset from the current value.
  612. * @see View#setTranslationZ(float)
  613. * @return This object, allowing calls to methods in this class to be chained.
  614. */
  615. public ViewPropertyAnimator translationZBy(float value) {
  616. animatePropertyBy(TRANSLATION_Z, value);
  617. return this;
  618. }
  619. /**
  620. * This method will cause the View's <code>scaleX</code> property to be animated to the
  621. * specified value. Animations already running on the property will be canceled.
  622. *
  623. * @param value The value to be animated to.
  624. * @see View#setScaleX(float)
  625. * @return This object, allowing calls to methods in this class to be chained.
  626. */
  627. public ViewPropertyAnimator scaleX(float value) {
  628. animateProperty(SCALE_X, value);
  629. return this;
  630. }
  631. /**
  632. * This method will cause the View's <code>scaleX</code> property to be animated by the
  633. * specified value. Animations already running on the property will be canceled.
  634. *
  635. * @param value The amount to be animated by, as an offset from the current value.
  636. * @see View#setScaleX(float)
  637. * @return This object, allowing calls to methods in this class to be chained.
  638. */
  639. public ViewPropertyAnimator scaleXBy(float value) {
  640. animatePropertyBy(SCALE_X, value);
  641. return this;
  642. }
  643. /**
  644. * This method will cause the View's <code>scaleY</code> property to be animated to the
  645. * specified value. Animations already running on the property will be canceled.
  646. *
  647. * @param value The value to be animated to.
  648. * @see View#setScaleY(float)
  649. * @return This object, allowing calls to methods in this class to be chained.
  650. */
  651. public ViewPropertyAnimator scaleY(float value) {
  652. animateProperty(SCALE_Y, value);
  653. return this;
  654. }
  655. /**
  656. * This method will cause the View's <code>scaleY</code> property to be animated by the
  657. * specified value. Animations already running on the property will be canceled.
  658. *
  659. * @param value The amount to be animated by, as an offset from the current value.
  660. * @see View#setScaleY(float)
  661. * @return This object, allowing calls to methods in this class to be chained.
  662. */
  663. public ViewPropertyAnimator scaleYBy(float value) {
  664. animatePropertyBy(SCALE_Y, value);
  665. return this;
  666. }
  667. /**
  668. * This method will cause the View's <code>alpha</code> property to be animated to the
  669. * specified value. Animations already running on the property will be canceled.
  670. *
  671. * @param value The value to be animated to.
  672. * @see View#setAlpha(float)
  673. * @return This object, allowing calls to methods in this class to be chained.
  674. */
  675. public ViewPropertyAnimator alpha(float value) {
  676. animateProperty(ALPHA, value);
  677. return this;
  678. }
  679. /**
  680. * This method will cause the View's <code>alpha</code> property to be animated by the
  681. * specified value. Animations already running on the property will be canceled.
  682. *
  683. * @param value The amount to be animated by, as an offset from the current value.
  684. * @see View#setAlpha(float)
  685. * @return This object, allowing calls to methods in this class to be chained.
  686. */
  687. public ViewPropertyAnimator alphaBy(float value) {
  688. animatePropertyBy(ALPHA, value);
  689. return this;
  690. }
  691. /**
  692. * The View associated with this ViewPropertyAnimator will have its
  693. * {@link View#setLayerType(int, android.graphics.Paint) layer type} set to
  694. * {@link View#LAYER_TYPE_HARDWARE} for the duration of the next animation.
  695. * As stated in the documentation for {@link View#LAYER_TYPE_HARDWARE},
  696. * the actual type of layer used internally depends on the runtime situation of the
  697. * view. If the activity and this view are hardware-accelerated, then the layer will be
  698. * accelerated as well. If the activity or the view is not accelerated, then the layer will
  699. * effectively be the same as {@link View#LAYER_TYPE_SOFTWARE}.
  700. *
  701. * <p>This state is not persistent, either on the View or on this ViewPropertyAnimator: the
  702. * layer type of the View will be restored when the animation ends to what it was when this
  703. * method was called, and this setting on ViewPropertyAnimator is only valid for the next
  704. * animation. Note that calling this method and then independently setting the layer type of
  705. * the View (by a direct call to {@link View#setLayerType(int, android.graphics.Paint)}) will
  706. * result in some inconsistency, including having the layer type restored to its pre-withLayer()
  707. * value when the animation ends.</p>
  708. *
  709. * @see View#setLayerType(int, android.graphics.Paint)
  710. * @return This object, allowing calls to methods in this class to be chained.
  711. */
  712. public ViewPropertyAnimator withLayer() {
  713. mPendingSetupAction= new Runnable() {
  714. @Override
  715. public void run() {
  716. mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
  717. if (mView.isAttachedToWindow()) {
  718. mView.buildLayer();
  719. }
  720. }
  721. };
  722. final int currentLayerType = mView.getLayerType();
  723. mPendingCleanupAction = new Runnable() {
  724. @Override
  725. public void run() {
  726. mView.setLayerType(currentLayerType, null);
  727. }
  728. };
  729. if (mAnimatorSetupMap == null) {
  730. mAnimatorSetupMap = new HashMap<Animator, Runnable>();
  731. }
  732. if (mAnimatorCleanupMap == null) {
  733. mAnimatorCleanupMap = new HashMap<Animator, Runnable>();
  734. }
  735. return this;
  736. }
  737. /**
  738. * Specifies an action to take place when the next animation runs. If there is a
  739. * {@link #setStartDelay(long) startDelay} set on this ViewPropertyAnimator, then the
  740. * action will run after that startDelay expires, when the actual animation begins.
  741. * This method, along with {@link #withEndAction(Runnable)}, is intended to help facilitate
  742. * choreographing ViewPropertyAnimator animations with other animations or actions
  743. * in the application.
  744. *
  745. * @param runnable The action to run when the next animation starts.
  746. * @return This object, allowing calls to methods in this class to be chained.
  747. */
  748. public ViewPropertyAnimator withStartAction(Runnable runnable) {
  749. mPendingOnStartAction = runnable;
  750. if (runnable != null && mAnimatorOnStartMap == null) {
  751. mAnimatorOnStartMap = new HashMap<Animator, Runnable>();
  752. }
  753. return this;
  754. }
  755. /**
  756. * Specifies an action to take place when the next animation ends. The action is only
  757. * run if the animation ends normally; if the ViewPropertyAnimator is canceled during
  758. * that animation, the runnable will not run.
  759. * This method, along with {@link #withStartAction(Runnable)}, is intended to help facilitate
  760. * choreographing ViewPropertyAnimator animations with other animations or actions
  761. * in the application.
  762. *
  763. * <p>For example, the following code animates a view to x=200 and then back to 0:</p>
  764. * <pre>
  765. * Runnable endAction = new Runnable() {
  766. * public void run() {
  767. * view.animate().x(0);
  768. * }
  769. * };
  770. * view.animate().x(200).withEndAction(endAction);
  771. * </pre>
  772. *
  773. * @param runnable The action to run when the next animation ends.
  774. * @return This object, allowing calls to methods in this class to be chained.
  775. */
  776. public ViewPropertyAnimator withEndAction(Runnable runnable) {
  777. mPendingOnEndAction = runnable;
  778. if (runnable != null && mAnimatorOnEndMap == null) {
  779. mAnimatorOnEndMap = new HashMap<Animator, Runnable>();
  780. }
  781. return this;
  782. }
  783. boolean hasActions() {
  784. return mPendingSetupAction != null
  785. || mPendingCleanupAction != null
  786. || mPendingOnStartAction != null
  787. || mPendingOnEndAction != null;
  788. }
  789. /**
  790. * Starts the underlying Animator for a set of properties. We use a single animator that
  791. * simply runs from 0 to 1, and then use that fractional value to set each property
  792. * value accordingly.
  793. */
  794. private void startAnimation() {
  795. if (mRTBackend != null && mRTBackend.startAnimation(this)) {
  796. return;
  797. }
  798. mView.setHasTransientState(true);
  799. ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
  800. ArrayList<NameValuesHolder> nameValueList =
  801. (ArrayList<NameValuesHolder>) mPendingAnimations.clone();
  802. mPendingAnimations.clear();
  803. int propertyMask = 0;
  804. int propertyCount = nameValueList.size();
  805. for (int i = 0; i < propertyCount; ++i) {
  806. NameValuesHolder nameValuesHolder = nameValueList.get(i);
  807. propertyMask |= nameValuesHolder.mNameConstant;
  808. }
  809. mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
  810. if (mPendingSetupAction != null) {
  811. mAnimatorSetupMap.put(animator, mPendingSetupAction);
  812. mPendingSetupAction = null;
  813. }
  814. if (mPendingCleanupAction != null) {
  815. mAnimatorCleanupMap.put(animator, mPendingCleanupAction);
  816. mPendingCleanupAction = null;
  817. }
  818. if (mPendingOnStartAction != null) {
  819. mAnimatorOnStartMap.put(animator, mPendingOnStartAction);
  820. mPendingOnStartAction = null;
  821. }
  822. if (mPendingOnEndAction != null) {
  823. mAnimatorOnEndMap.put(animator, mPendingOnEndAction);
  824. mPendingOnEndAction = null;
  825. }
  826. animator.addUpdateListener(mAnimatorEventListener);
  827. animator.addListener(mAnimatorEventListener);
  828. if (mStartDelaySet) {
  829. animator.setStartDelay(mStartDelay);
  830. }
  831. if (mDurationSet) {
  832. animator.setDuration(mDuration);
  833. }
  834. if (mInterpolatorSet) {
  835. animator.setInterpolator(mInterpolator);
  836. }
  837. animator.start();
  838. }
  839. /**
  840. * Utility function, called by the various x(), y(), etc. methods. This stores the
  841. * constant name for the property along with the from/delta values that will be used to
  842. * calculate and set the property during the animation. This structure is added to the
  843. * pending animations, awaiting the eventual start() of the underlying animator. A
  844. * Runnable is posted to start the animation, and any pending such Runnable is canceled
  845. * (which enables us to end up starting just one animator for all of the properties
  846. * specified at one time).
  847. *
  848. * @param constantName The specifier for the property being animated
  849. * @param toValue The value to which the property will animate
  850. */
  851. private void animateProperty(int constantName, float toValue) {
  852. float fromValue = getValue(constantName);
  853. float deltaValue = toValue - fromValue;
  854. animatePropertyBy(constantName, fromValue, deltaValue);
  855. }
  856. /**
  857. * Utility function, called by the various xBy(), yBy(), etc. methods. This method is
  858. * just like animateProperty(), except the value is an offset from the property's
  859. * current value, instead of an absolute "to" value.
  860. *
  861. * @param constantName The specifier for the property being animated
  862. * @param byValue The amount by which the property will change
  863. */
  864. private void animatePropertyBy(int constantName, float byValue) {
  865. float fromValue = getValue(constantName);
  866. animatePropertyBy(constantName, fromValue, byValue);
  867. }
  868. /**
  869. * Utility function, called by animateProperty() and animatePropertyBy(), which handles the
  870. * details of adding a pending animation and posting the request to start the animation.
  871. *
  872. * @param constantName The specifier for the property being animated
  873. * @param startValue The starting value of the property
  874. * @param byValue The amount by which the property will change
  875. */
  876. private void animatePropertyBy(int constantName, float startValue, float byValue) {
  877. // First, cancel any existing animations on this property
  878. if (mAnimatorMap.size() > 0) {
  879. Animator animatorToCancel = null;
  880. Set<Animator> animatorSet = mAnimatorMap.keySet();
  881. for (Animator runningAnim : animatorSet) {
  882. PropertyBundle bundle = mAnimatorMap.get(runningAnim);
  883. if (bundle.cancel(constantName)) {
  884. // property was canceled - cancel the animation if it's now empty
  885. // Note that it's safe to break out here because every new animation
  886. // on a property will cancel a previous animation on that property, so
  887. // there can only ever be one such animation running.
  888. if (bundle.mPropertyMask == NONE) {
  889. // the animation is no longer changing anything - cancel it
  890. animatorToCancel = runningAnim;
  891. break;
  892. }
  893. }
  894. }
  895. if (animatorToCancel != null) {
  896. animatorToCancel.cancel();
  897. }
  898. }
  899. NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
  900. mPendingAnimations.add(nameValuePair);
  901. mView.removeCallbacks(mAnimationStarter);
  902. mView.postOnAnimation(mAnimationStarter);
  903. }
  904. /**
  905. * This method handles setting the property values directly in the View object's fields.
  906. * propertyConstant tells it which property should be set, value is the value to set
  907. * the property to.
  908. *
  909. * @param propertyConstant The property to be set
  910. * @param value The value to set the property to
  911. */
  912. private void setValue(int propertyConstant, float value) {
  913. final View.TransformationInfo info = mView.mTransformationInfo;
  914. final RenderNode renderNode = mView.mRenderNode;
  915. switch (propertyConstant) {
  916. case TRANSLATION_X:
  917. renderNode.setTranslationX(value);
  918. break;
  919. case TRANSLATION_Y:
  920. renderNode.setTranslationY(value);
  921. break;
  922. case TRANSLATION_Z:
  923. renderNode.setTranslationZ(value);
  924. break;
  925. case ROTATION:
  926. renderNode.setRotation(value);
  927. break;
  928. case ROTATION_X:
  929. renderNode.setRotationX(value);
  930. break;
  931. case ROTATION_Y:
  932. renderNode.setRotationY(value);
  933. break;
  934. case SCALE_X:
  935. renderNode.setScaleX(value);
  936. break;
  937. case SCALE_Y:
  938. renderNode.setScaleY(value);
  939. break;
  940. case X:
  941. renderNode.setTranslationX(value - mView.mLeft);
  942. break;
  943. case Y:
  944. renderNode.setTranslationY(value - mView.mTop);
  945. break;
  946. case Z:
  947. renderNode.setTranslationZ(value - renderNode.getElevation());
  948. break;
  949. case ALPHA:
  950. info.mAlpha = value;
  951. renderNode.setAlpha(value);
  952. break;
  953. }
  954. }
  955. /**
  956. * This method gets the value of the named property from the View object.
  957. *
  958. * @param propertyConstant The property whose value should be returned
  959. * @return float The value of the named property
  960. */
  961. private float getValue(int propertyConstant) {
  962. final RenderNode node = mView.mRenderNode;
  963. switch (propertyConstant) {
  964. case TRANSLATION_X:
  965. return node.getTranslationX();
  966. case TRANSLATION_Y:
  967. return node.getTranslationY();
  968. case TRANSLATION_Z:
  969. return node.getTranslationZ();
  970. case ROTATION:
  971. return node.getRotation();
  972. case ROTATION_X:
  973. return node.getRotationX();
  974. case ROTATION_Y:
  975. return node.getRotationY();
  976. case SCALE_X:
  977. return node.getScaleX();
  978. case SCALE_Y:
  979. return node.getScaleY();
  980. case X:
  981. return mView.mLeft + node.getTranslationX();
  982. case Y:
  983. return mView.mTop + node.getTranslationY();
  984. case Z:
  985. return node.getElevation() + node.getTranslationZ();
  986. case ALPHA:
  987. return mView.mTransformationInfo.mAlpha;
  988. }
  989. return 0;
  990. }
  991. /**
  992. * Utility class that handles the various Animator events. The only ones we care
  993. * about are the end event (which we use to clean up the animator map when an animator
  994. * finishes) and the update event (which we use to calculate the current value of each
  995. * property and then set it on the view object).
  996. */
  997. private class AnimatorEventListener
  998. implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
  999. @Override
  1000. public void onAnimationStart(Animator animation) {
  1001. if (mAnimatorSetupMap != null) {
  1002. Runnable r = mAnimatorSetupMap.get(animation);
  1003. if (r != null) {
  1004. r.run();
  1005. }
  1006. mAnimatorSetupMap.remove(animation);
  1007. }
  1008. if (mAnimatorOnStartMap != null) {
  1009. Runnable r = mAnimatorOnStartMap.get(animation);
  1010. if (r != null) {
  1011. r.run();
  1012. }
  1013. mAnimatorOnStartMap.remove(animation);
  1014. }
  1015. if (mListener != null) {
  1016. mListener.onAnimationStart(animation);
  1017. }
  1018. }
  1019. @Override
  1020. public void onAnimationCancel(Animator animation) {
  1021. if (mListener != null) {
  1022. mListener.onAnimationCancel(animation);
  1023. }
  1024. if (mAnimatorOnEndMap != null) {
  1025. mAnimatorOnEndMap.remove(animation);
  1026. }
  1027. }
  1028. @Override
  1029. public void onAnimationRepeat(Animator animation) {
  1030. if (mListener != null) {
  1031. mListener.onAnimationRepeat(animation);
  1032. }
  1033. }
  1034. @Override
  1035. public void onAnimationEnd(Animator animation) {
  1036. mView.setHasTransientState(false);
  1037. if (mListener != null) {
  1038. mListener.onAnimationEnd(animation);
  1039. }
  1040. if (mAnimatorOnEndMap != null) {
  1041. Runnable r = mAnimatorOnEndMap.get(animation);
  1042. if (r != null) {
  1043. r.run();
  1044. }
  1045. mAnimatorOnEndMap.remove(animation);
  1046. }
  1047. if (mAnimatorCleanupMap != null) {
  1048. Runnable r = mAnimatorCleanupMap.get(animation);
  1049. if (r != null) {
  1050. r.run();
  1051. }
  1052. mAnimatorCleanupMap.remove(animation);
  1053. }
  1054. mAnimatorMap.remove(animation);
  1055. }
  1056. /**
  1057. * Calculate the current value for each property and set it on the view. Invalidate
  1058. * the view object appropriately, depending on which properties are being animated.
  1059. *
  1060. * @param animation The animator associated with the properties that need to be
  1061. * set. This animator holds the animation fraction which we will use to calculate
  1062. * the current value of each property.
  1063. */
  1064. @Override
  1065. public void onAnimationUpdate(ValueAnimator animation) {
  1066. PropertyBundle propertyBundle = mAnimatorMap.get(animation);
  1067. if (propertyBundle == null) {
  1068. // Shouldn't happen, but just to play it safe
  1069. return;
  1070. }
  1071. boolean hardwareAccelerated = mView.isHardwareAccelerated();
  1072. // alpha requires slightly different treatment than the other (transform) properties.
  1073. // The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
  1074. // logic is dependent on how the view handles an internal call to onSetAlpha().
  1075. // We track what kinds of properties are set, and how alpha is handled when it is
  1076. // set, and perform the invalidation steps appropriately.
  1077. boolean alphaHandled = false;
  1078. if (!hardwareAccelerated) {
  1079. mView.invalidateParentCaches();
  1080. }
  1081. float fraction = animation.getAnimatedFraction();
  1082. int propertyMask = propertyBundle.mPropertyMask;
  1083. if ((propertyMask & TRANSFORM_MASK) != 0) {
  1084. mView.invalidateViewProperty(hardwareAccelerated, false);
  1085. }
  1086. ArrayList<NameValuesHolder> valueList = propertyBundle.mNameValuesHolder;
  1087. if (valueList != null) {
  1088. int count = valueList.size();
  1089. for (int i = 0; i < count; ++i) {
  1090. NameValuesHolder values = valueList.get(i);
  1091. float value = values.mFromValue + fraction * values.mDeltaValue;
  1092. if (values.mNameConstant == ALPHA) {
  1093. alphaHandled = mView.setAlphaNoInvalidation(value);
  1094. } else {
  1095. setValue(values.mNameConstant, value);
  1096. }
  1097. }
  1098. }
  1099. if ((propertyMask & TRANSFORM_MASK) != 0) {
  1100. if (!hardwareAccelerated) {
  1101. mView.mPrivateFlags |= View.PFLAG_DRAWN; // force another invalidation
  1102. }
  1103. }
  1104. // invalidate(false) in all cases except if alphaHandled gets set to true
  1105. // via the call to setAlphaNoInvalidation(), above
  1106. if (alphaHandled) {
  1107. mView.invalidate(true);
  1108. } else {
  1109. mView.invalidateViewProperty(false, false);
  1110. }
  1111. if (mUpdateListener != null) {
  1112. mUpdateListener.onAnimationUpdate(animation);
  1113. }
  1114. }
  1115. }
  1116. }