blob: 859e9a43f7c279010f4400da7460158f75d8fc8a [file] [log] [blame]
Chet Haasea00f3862011-02-22 06:34:40 -08001/*
Chet Haased666cf32011-03-01 07:31:30 -08002 * Copyright (C) 2011 The Android Open Source Project
Chet Haasea00f3862011-02-22 06:34:40 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
19import android.animation.Animator;
Chet Haasea00f3862011-02-22 06:34:40 -080020import android.animation.TimeInterpolator;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070021import android.animation.ValueAnimator;
John Reck32f140aa62018-10-04 15:08:24 -070022import android.graphics.RenderNode;
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070023
Chet Haasea00f3862011-02-22 06:34:40 -080024import java.util.ArrayList;
25import java.util.HashMap;
26import java.util.Set;
27
28/**
29 * This class enables automatic and optimized animation of select properties on View objects.
30 * If only one or two properties on a View object are being animated, then using an
31 * {@link android.animation.ObjectAnimator} is fine; the property setters called by ObjectAnimator
32 * are well equipped to do the right thing to set the property and invalidate the view
33 * appropriately. But if several properties are animated simultaneously, or if you just want a
34 * more convenient syntax to animate a specific property, then ViewPropertyAnimator might be
35 * more well-suited to the task.
36 *
Chet Haased666cf32011-03-01 07:31:30 -080037 * <p>This class may provide better performance for several simultaneous animations, because
38 * it will optimize invalidate calls to take place only once for several properties instead of each
39 * animated property independently causing its own invalidation. Also, the syntax of using this
Chet Haasea00f3862011-02-22 06:34:40 -080040 * class could be easier to use because the caller need only tell the View object which
Chet Haased666cf32011-03-01 07:31:30 -080041 * property to animate, and the value to animate either to or by, and this class handles the
Chet Haasea00f3862011-02-22 06:34:40 -080042 * details of configuring the underlying Animator class and starting it.</p>
43 *
44 * <p>This class is not constructed by the caller, but rather by the View whose properties
45 * it will animate. Calls to {@link android.view.View#animate()} will return a reference
46 * to the appropriate ViewPropertyAnimator object for that View.</p>
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070047 *
Chet Haasea00f3862011-02-22 06:34:40 -080048 */
49public class ViewPropertyAnimator {
50
51 /**
52 * The View whose properties are being animated by this class. This is set at
53 * construction time.
54 */
John Reck44244ff2014-06-20 14:44:58 -070055 final View mView;
Chet Haasea00f3862011-02-22 06:34:40 -080056
57 /**
58 * The duration of the underlying Animator object. By default, we don't set the duration
59 * on the Animator and just use its default duration. If the duration is ever set on this
60 * Animator, then we use the duration that it was set to.
61 */
62 private long mDuration;
63
64 /**
65 * A flag indicating whether the duration has been set on this object. If not, we don't set
66 * the duration on the underlying Animator, but instead just use its default duration.
67 */
68 private boolean mDurationSet = false;
69
70 /**
Chet Haase8d5f8082011-05-24 08:03:16 -070071 * The startDelay of the underlying Animator object. By default, we don't set the startDelay
72 * on the Animator and just use its default startDelay. If the startDelay is ever set on this
73 * Animator, then we use the startDelay that it was set to.
74 */
75 private long mStartDelay = 0;
76
77 /**
78 * A flag indicating whether the startDelay has been set on this object. If not, we don't set
79 * the startDelay on the underlying Animator, but instead just use its default startDelay.
80 */
81 private boolean mStartDelaySet = false;
82
83 /**
Chet Haasea00f3862011-02-22 06:34:40 -080084 * The interpolator of the underlying Animator object. By default, we don't set the interpolator
Vladislav Kaznacheev78f146f2015-06-15 06:58:59 +000085 * on the Animator and just use its default interpolator. If the interpolator is ever set on
86 * this Animator, then we use the interpolator that it was set to.
Chet Haasea00f3862011-02-22 06:34:40 -080087 */
88 private TimeInterpolator mInterpolator;
89
90 /**
Vladislav Kaznacheev78f146f2015-06-15 06:58:59 +000091 * A flag indicating whether the interpolator has been set on this object. If not, we don't set
92 * the interpolator on the underlying Animator, but instead just use its default interpolator.
93 */
94 private boolean mInterpolatorSet = false;
95
96 /**
Chet Haase87f4ae62013-09-06 18:29:56 -070097 * Listener for the lifecycle events of the underlying ValueAnimator object.
Chet Haasea00f3862011-02-22 06:34:40 -080098 */
99 private Animator.AnimatorListener mListener = null;
100
101 /**
Chet Haase87f4ae62013-09-06 18:29:56 -0700102 * Listener for the update events of the underlying ValueAnimator object.
103 */
104 private ValueAnimator.AnimatorUpdateListener mUpdateListener = null;
105
106 /**
Cyril Mottierd40acfb2013-07-25 10:08:29 +0200107 * A lazily-created ValueAnimator used in order to get some default animator properties
108 * (duration, start delay, interpolator, etc.).
109 */
110 private ValueAnimator mTempValueAnimator;
111
112 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800113 * This listener is the mechanism by which the underlying Animator causes changes to the
114 * properties currently being animated, as well as the cleanup after an animation is
115 * complete.
116 */
117 private AnimatorEventListener mAnimatorEventListener = new AnimatorEventListener();
118
119 /**
120 * This list holds the properties that have been asked to animate. We allow the caller to
121 * request several animations prior to actually starting the underlying animator. This
122 * enables us to run one single animator to handle several properties in parallel. Each
123 * property is tossed onto the pending list until the animation actually starts (which is
124 * done by posting it onto mView), at which time the pending list is cleared and the properties
125 * on that list are added to the list of properties associated with that animator.
126 */
127 ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();
Chet Haasec1ca6652012-01-31 07:33:48 -0800128 private Runnable mPendingSetupAction;
129 private Runnable mPendingCleanupAction;
130 private Runnable mPendingOnStartAction;
131 private Runnable mPendingOnEndAction;
Chet Haasea00f3862011-02-22 06:34:40 -0800132
133 /**
134 * Constants used to associate a property being requested and the mechanism used to set
Chet Haased666cf32011-03-01 07:31:30 -0800135 * the property (this class calls directly into View to set the properties in question).
Chet Haasea00f3862011-02-22 06:34:40 -0800136 */
John Recke45b1fd2014-04-15 09:50:16 -0700137 static final int NONE = 0x0000;
138 static final int TRANSLATION_X = 0x0001;
139 static final int TRANSLATION_Y = 0x0002;
140 static final int TRANSLATION_Z = 0x0004;
141 static final int SCALE_X = 0x0008;
142 static final int SCALE_Y = 0x0010;
143 static final int ROTATION = 0x0020;
144 static final int ROTATION_X = 0x0040;
145 static final int ROTATION_Y = 0x0080;
146 static final int X = 0x0100;
147 static final int Y = 0x0200;
148 static final int Z = 0x0400;
149 static final int ALPHA = 0x0800;
Chet Haasea00f3862011-02-22 06:34:40 -0800150
Chris Craikf57776b2013-10-25 18:30:17 -0700151 private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | TRANSLATION_Z |
Chris Craikcc39e162014-04-25 18:34:11 -0700152 SCALE_X | SCALE_Y | ROTATION | ROTATION_X | ROTATION_Y | X | Y | Z;
Chet Haasea00f3862011-02-22 06:34:40 -0800153
154 /**
155 * The mechanism by which the user can request several properties that are then animated
156 * together works by posting this Runnable to start the underlying Animator. Every time
157 * a property animation is requested, we cancel any previous postings of the Runnable
158 * and re-post it. This means that we will only ever run the Runnable (and thus start the
159 * underlying animator) after the caller is done setting the properties that should be
160 * animated together.
161 */
162 private Runnable mAnimationStarter = new Runnable() {
163 @Override
164 public void run() {
165 startAnimation();
166 }
167 };
168
169 /**
170 * This class holds information about the overall animation being run on the set of
171 * properties. The mask describes which properties are being animated and the
172 * values holder is the list of all property/value objects.
173 */
174 private static class PropertyBundle {
175 int mPropertyMask;
176 ArrayList<NameValuesHolder> mNameValuesHolder;
Chet Haaseba592d202011-02-25 11:35:17 -0800177
Chet Haasea00f3862011-02-22 06:34:40 -0800178 PropertyBundle(int propertyMask, ArrayList<NameValuesHolder> nameValuesHolder) {
179 mPropertyMask = propertyMask;
180 mNameValuesHolder = nameValuesHolder;
181 }
Chet Haaseba592d202011-02-25 11:35:17 -0800182
183 /**
184 * Removes the given property from being animated as a part of this
185 * PropertyBundle. If the property was a part of this bundle, it returns
186 * true to indicate that it was, in fact, canceled. This is an indication
187 * to the caller that a cancellation actually occurred.
188 *
189 * @param propertyConstant The property whose cancellation is requested.
190 * @return true if the given property is a part of this bundle and if it
191 * has therefore been canceled.
192 */
193 boolean cancel(int propertyConstant) {
194 if ((mPropertyMask & propertyConstant) != 0 && mNameValuesHolder != null) {
195 int count = mNameValuesHolder.size();
196 for (int i = 0; i < count; ++i) {
197 NameValuesHolder nameValuesHolder = mNameValuesHolder.get(i);
198 if (nameValuesHolder.mNameConstant == propertyConstant) {
199 mNameValuesHolder.remove(i);
200 mPropertyMask &= ~propertyConstant;
201 return true;
202 }
203 }
204 }
205 return false;
206 }
Chet Haasea00f3862011-02-22 06:34:40 -0800207 }
208
209 /**
210 * This list tracks the list of properties being animated by any particular animator.
211 * In most situations, there would only ever be one animator running at a time. But it is
212 * possible to request some properties to animate together, then while those properties
213 * are animating, to request some other properties to animate together. The way that
214 * works is by having this map associate the group of properties being animated with the
215 * animator handling the animation. On every update event for an Animator, we ask the
216 * map for the associated properties and set them accordingly.
217 */
218 private HashMap<Animator, PropertyBundle> mAnimatorMap =
219 new HashMap<Animator, PropertyBundle>();
Chet Haasec1ca6652012-01-31 07:33:48 -0800220 private HashMap<Animator, Runnable> mAnimatorSetupMap;
221 private HashMap<Animator, Runnable> mAnimatorCleanupMap;
222 private HashMap<Animator, Runnable> mAnimatorOnStartMap;
223 private HashMap<Animator, Runnable> mAnimatorOnEndMap;
Chet Haasea00f3862011-02-22 06:34:40 -0800224
225 /**
226 * This is the information we need to set each property during the animation.
227 * mNameConstant is used to set the appropriate field in View, and the from/delta
228 * values are used to calculate the animated value for a given animation fraction
229 * during the animation.
230 */
John Reck918988c2014-05-19 10:28:35 -0700231 static class NameValuesHolder {
Chet Haasea00f3862011-02-22 06:34:40 -0800232 int mNameConstant;
233 float mFromValue;
234 float mDeltaValue;
235 NameValuesHolder(int nameConstant, float fromValue, float deltaValue) {
236 mNameConstant = nameConstant;
237 mFromValue = fromValue;
238 mDeltaValue = deltaValue;
239 }
240 }
241
242 /**
243 * Constructor, called by View. This is private by design, as the user should only
244 * get a ViewPropertyAnimator by calling View.animate().
245 *
246 * @param view The View associated with this ViewPropertyAnimator
247 */
248 ViewPropertyAnimator(View view) {
249 mView = view;
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700250 view.ensureTransformationInfo();
Chet Haasea00f3862011-02-22 06:34:40 -0800251 }
252
253 /**
254 * Sets the duration for the underlying animator that animates the requested properties.
255 * By default, the animator uses the default value for ValueAnimator. Calling this method
256 * will cause the declared value to be used instead.
257 * @param duration The length of ensuing property animations, in milliseconds. The value
258 * cannot be negative.
259 * @return This object, allowing calls to methods in this class to be chained.
260 */
261 public ViewPropertyAnimator setDuration(long duration) {
262 if (duration < 0) {
263 throw new IllegalArgumentException("Animators cannot have negative duration: " +
264 duration);
265 }
266 mDurationSet = true;
267 mDuration = duration;
268 return this;
269 }
270
271 /**
Chet Haase8d5f8082011-05-24 08:03:16 -0700272 * Returns the current duration of property animations. If the duration was set on this
273 * object, that value is returned. Otherwise, the default value of the underlying Animator
274 * is returned.
275 *
276 * @see #setDuration(long)
277 * @return The duration of animations, in milliseconds.
278 */
279 public long getDuration() {
Chet Haasecbbd93a2011-08-08 17:34:25 -0700280 if (mDurationSet) {
281 return mDuration;
Chet Haase8d5f8082011-05-24 08:03:16 -0700282 } else {
283 // Just return the default from ValueAnimator, since that's what we'd get if
284 // the value has not been set otherwise
Cyril Mottierd40acfb2013-07-25 10:08:29 +0200285 if (mTempValueAnimator == null) {
286 mTempValueAnimator = new ValueAnimator();
287 }
288 return mTempValueAnimator.getDuration();
Chet Haase8d5f8082011-05-24 08:03:16 -0700289 }
290 }
291
292 /**
293 * Returns the current startDelay of property animations. If the startDelay was set on this
294 * object, that value is returned. Otherwise, the default value of the underlying Animator
295 * is returned.
296 *
297 * @see #setStartDelay(long)
298 * @return The startDelay of animations, in milliseconds.
299 */
300 public long getStartDelay() {
301 if (mStartDelaySet) {
302 return mStartDelay;
303 } else {
304 // Just return the default from ValueAnimator (0), since that's what we'd get if
305 // the value has not been set otherwise
306 return 0;
307 }
308 }
309
310 /**
311 * Sets the startDelay for the underlying animator that animates the requested properties.
312 * By default, the animator uses the default value for ValueAnimator. Calling this method
313 * will cause the declared value to be used instead.
314 * @param startDelay The delay of ensuing property animations, in milliseconds. The value
315 * cannot be negative.
316 * @return This object, allowing calls to methods in this class to be chained.
317 */
318 public ViewPropertyAnimator setStartDelay(long startDelay) {
319 if (startDelay < 0) {
Cyril Mottier772bafa2013-10-02 16:57:57 +0200320 throw new IllegalArgumentException("Animators cannot have negative start " +
321 "delay: " + startDelay);
Chet Haase8d5f8082011-05-24 08:03:16 -0700322 }
323 mStartDelaySet = true;
324 mStartDelay = startDelay;
325 return this;
326 }
327
328 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800329 * Sets the interpolator for the underlying animator that animates the requested properties.
330 * By default, the animator uses the default interpolator for ValueAnimator. Calling this method
331 * will cause the declared object to be used instead.
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700332 *
John Recka0b13bd2014-07-01 08:34:47 -0700333 * @param interpolator The TimeInterpolator to be used for ensuing property animations. A value
334 * of <code>null</code> will result in linear interpolation.
Chet Haasea00f3862011-02-22 06:34:40 -0800335 * @return This object, allowing calls to methods in this class to be chained.
336 */
337 public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) {
Vladislav Kaznacheev78f146f2015-06-15 06:58:59 +0000338 mInterpolatorSet = true;
Chet Haasea00f3862011-02-22 06:34:40 -0800339 mInterpolator = interpolator;
340 return this;
341 }
342
343 /**
Chet Haase430742f2013-04-12 11:18:36 -0700344 * Returns the timing interpolator that this animation uses.
345 *
346 * @return The timing interpolator for this animation.
347 */
348 public TimeInterpolator getInterpolator() {
Vladislav Kaznacheev78f146f2015-06-15 06:58:59 +0000349 if (mInterpolatorSet) {
Cyril Mottierd40acfb2013-07-25 10:08:29 +0200350 return mInterpolator;
351 } else {
352 // Just return the default from ValueAnimator, since that's what we'd get if
353 // the value has not been set otherwise
354 if (mTempValueAnimator == null) {
355 mTempValueAnimator = new ValueAnimator();
356 }
357 return mTempValueAnimator.getInterpolator();
358 }
Chet Haase430742f2013-04-12 11:18:36 -0700359 }
360
361 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800362 * Sets a listener for events in the underlying Animators that run the property
363 * animations.
364 *
Chet Haase87f4ae62013-09-06 18:29:56 -0700365 * @see Animator.AnimatorListener
366 *
367 * @param listener The listener to be called with AnimatorListener events. A value of
368 * <code>null</code> removes any existing listener.
Chet Haasea00f3862011-02-22 06:34:40 -0800369 * @return This object, allowing calls to methods in this class to be chained.
370 */
371 public ViewPropertyAnimator setListener(Animator.AnimatorListener listener) {
372 mListener = listener;
373 return this;
374 }
375
John Reck918988c2014-05-19 10:28:35 -0700376 Animator.AnimatorListener getListener() {
377 return mListener;
378 }
379
Chet Haasea00f3862011-02-22 06:34:40 -0800380 /**
Chet Haase87f4ae62013-09-06 18:29:56 -0700381 * Sets a listener for update events in the underlying ValueAnimator that runs
382 * the property animations. Note that the underlying animator is animating between
383 * 0 and 1 (these values are then turned into the actual property values internally
384 * by ViewPropertyAnimator). So the animator cannot give information on the current
385 * values of the properties being animated by this ViewPropertyAnimator, although
386 * the view object itself can be queried to get the current values.
387 *
388 * @see android.animation.ValueAnimator.AnimatorUpdateListener
389 *
390 * @param listener The listener to be called with update events. A value of
391 * <code>null</code> removes any existing listener.
392 * @return This object, allowing calls to methods in this class to be chained.
393 */
394 public ViewPropertyAnimator setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) {
395 mUpdateListener = listener;
396 return this;
397 }
398
John Reck918988c2014-05-19 10:28:35 -0700399 ValueAnimator.AnimatorUpdateListener getUpdateListener() {
400 return mUpdateListener;
401 }
402
Chet Haase87f4ae62013-09-06 18:29:56 -0700403 /**
Chet Haase8d5f8082011-05-24 08:03:16 -0700404 * Starts the currently pending property animations immediately. Calling <code>start()</code>
405 * is optional because all animations start automatically at the next opportunity. However,
406 * if the animations are needed to start immediately and synchronously (not at the time when
407 * the next event is processed by the hierarchy, which is when the animations would begin
408 * otherwise), then this method can be used.
409 */
410 public void start() {
Michael Jurka500998d2012-05-13 15:35:02 -0700411 mView.removeCallbacks(mAnimationStarter);
Chet Haase8d5f8082011-05-24 08:03:16 -0700412 startAnimation();
413 }
414
415 /**
416 * Cancels all property animations that are currently running or pending.
417 */
418 public void cancel() {
419 if (mAnimatorMap.size() > 0) {
420 HashMap<Animator, PropertyBundle> mAnimatorMapCopy =
421 (HashMap<Animator, PropertyBundle>)mAnimatorMap.clone();
422 Set<Animator> animatorSet = mAnimatorMapCopy.keySet();
423 for (Animator runningAnim : animatorSet) {
424 runningAnim.cancel();
425 }
426 }
427 mPendingAnimations.clear();
Chet Haase5637b7d2014-08-28 07:53:59 -0700428 mPendingSetupAction = null;
429 mPendingCleanupAction = null;
430 mPendingOnStartAction = null;
431 mPendingOnEndAction = null;
Chet Haase3a000a52011-06-16 13:55:11 -0700432 mView.removeCallbacks(mAnimationStarter);
Chet Haase8d5f8082011-05-24 08:03:16 -0700433 }
434
435 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800436 * This method will cause the View's <code>x</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800437 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800438 *
439 * @param value The value to be animated to.
440 * @see View#setX(float)
441 * @return This object, allowing calls to methods in this class to be chained.
442 */
443 public ViewPropertyAnimator x(float value) {
444 animateProperty(X, value);
445 return this;
446 }
447
448 /**
449 * This method will cause the View's <code>x</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800450 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800451 *
452 * @param value The amount to be animated by, as an offset from the current value.
453 * @see View#setX(float)
454 * @return This object, allowing calls to methods in this class to be chained.
455 */
456 public ViewPropertyAnimator xBy(float value) {
457 animatePropertyBy(X, value);
458 return this;
459 }
460
461 /**
462 * This method will cause the View's <code>y</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800463 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800464 *
465 * @param value The value to be animated to.
466 * @see View#setY(float)
467 * @return This object, allowing calls to methods in this class to be chained.
468 */
469 public ViewPropertyAnimator y(float value) {
470 animateProperty(Y, value);
471 return this;
472 }
473
474 /**
475 * This method will cause the View's <code>y</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800476 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800477 *
478 * @param value The amount to be animated by, as an offset from the current value.
479 * @see View#setY(float)
480 * @return This object, allowing calls to methods in this class to be chained.
481 */
482 public ViewPropertyAnimator yBy(float value) {
483 animatePropertyBy(Y, value);
484 return this;
485 }
486
487 /**
Chris Craikcc39e162014-04-25 18:34:11 -0700488 * This method will cause the View's <code>z</code> property to be animated to the
489 * specified value. Animations already running on the property will be canceled.
490 *
491 * @param value The value to be animated to.
492 * @see View#setZ(float)
493 * @return This object, allowing calls to methods in this class to be chained.
494 */
495 public ViewPropertyAnimator z(float value) {
496 animateProperty(Z, value);
497 return this;
498 }
499
500 /**
501 * This method will cause the View's <code>z</code> property to be animated by the
502 * specified value. Animations already running on the property will be canceled.
503 *
504 * @param value The amount to be animated by, as an offset from the current value.
505 * @see View#setZ(float)
506 * @return This object, allowing calls to methods in this class to be chained.
507 */
508 public ViewPropertyAnimator zBy(float value) {
509 animatePropertyBy(Z, value);
510 return this;
511 }
512
513 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800514 * This method will cause the View's <code>rotation</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800515 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800516 *
517 * @param value The value to be animated to.
518 * @see View#setRotation(float)
519 * @return This object, allowing calls to methods in this class to be chained.
520 */
521 public ViewPropertyAnimator rotation(float value) {
522 animateProperty(ROTATION, value);
523 return this;
524 }
525
526 /**
527 * This method will cause the View's <code>rotation</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800528 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800529 *
530 * @param value The amount to be animated by, as an offset from the current value.
531 * @see View#setRotation(float)
532 * @return This object, allowing calls to methods in this class to be chained.
533 */
534 public ViewPropertyAnimator rotationBy(float value) {
535 animatePropertyBy(ROTATION, value);
536 return this;
537 }
538
539 /**
540 * This method will cause the View's <code>rotationX</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800541 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800542 *
543 * @param value The value to be animated to.
544 * @see View#setRotationX(float)
545 * @return This object, allowing calls to methods in this class to be chained.
546 */
547 public ViewPropertyAnimator rotationX(float value) {
548 animateProperty(ROTATION_X, value);
549 return this;
550 }
551
552 /**
553 * This method will cause the View's <code>rotationX</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800554 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800555 *
556 * @param value The amount to be animated by, as an offset from the current value.
557 * @see View#setRotationX(float)
558 * @return This object, allowing calls to methods in this class to be chained.
559 */
560 public ViewPropertyAnimator rotationXBy(float value) {
561 animatePropertyBy(ROTATION_X, value);
562 return this;
563 }
564
565 /**
566 * This method will cause the View's <code>rotationY</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800567 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800568 *
569 * @param value The value to be animated to.
570 * @see View#setRotationY(float)
571 * @return This object, allowing calls to methods in this class to be chained.
572 */
573 public ViewPropertyAnimator rotationY(float value) {
574 animateProperty(ROTATION_Y, value);
575 return this;
576 }
577
578 /**
579 * This method will cause the View's <code>rotationY</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800580 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800581 *
582 * @param value The amount to be animated by, as an offset from the current value.
583 * @see View#setRotationY(float)
584 * @return This object, allowing calls to methods in this class to be chained.
585 */
586 public ViewPropertyAnimator rotationYBy(float value) {
587 animatePropertyBy(ROTATION_Y, value);
588 return this;
589 }
590
591 /**
592 * This method will cause the View's <code>translationX</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800593 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800594 *
595 * @param value The value to be animated to.
596 * @see View#setTranslationX(float)
597 * @return This object, allowing calls to methods in this class to be chained.
598 */
599 public ViewPropertyAnimator translationX(float value) {
600 animateProperty(TRANSLATION_X, value);
601 return this;
602 }
603
604 /**
605 * This method will cause the View's <code>translationX</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800606 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800607 *
608 * @param value The amount to be animated by, as an offset from the current value.
609 * @see View#setTranslationX(float)
610 * @return This object, allowing calls to methods in this class to be chained.
611 */
612 public ViewPropertyAnimator translationXBy(float value) {
613 animatePropertyBy(TRANSLATION_X, value);
614 return this;
615 }
616
617 /**
618 * This method will cause the View's <code>translationY</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800619 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800620 *
621 * @param value The value to be animated to.
622 * @see View#setTranslationY(float)
623 * @return This object, allowing calls to methods in this class to be chained.
624 */
625 public ViewPropertyAnimator translationY(float value) {
626 animateProperty(TRANSLATION_Y, value);
627 return this;
628 }
629
630 /**
631 * This method will cause the View's <code>translationY</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800632 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800633 *
634 * @param value The amount to be animated by, as an offset from the current value.
635 * @see View#setTranslationY(float)
636 * @return This object, allowing calls to methods in this class to be chained.
637 */
638 public ViewPropertyAnimator translationYBy(float value) {
639 animatePropertyBy(TRANSLATION_Y, value);
640 return this;
641 }
642
643 /**
Chris Craikd863a102013-12-19 13:31:15 -0800644 * This method will cause the View's <code>translationZ</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#setTranslationZ(float)
649 * @return This object, allowing calls to methods in this class to be chained.
650 */
651 public ViewPropertyAnimator translationZ(float value) {
652 animateProperty(TRANSLATION_Z, value);
653 return this;
654 }
655
656 /**
657 * This method will cause the View's <code>translationZ</code> property to be animated by the
658 * specified value. Animations already running on the property will be canceled.
659 *
660 * @param value The amount to be animated by, as an offset from the current value.
661 * @see View#setTranslationZ(float)
662 * @return This object, allowing calls to methods in this class to be chained.
663 */
664 public ViewPropertyAnimator translationZBy(float value) {
665 animatePropertyBy(TRANSLATION_Z, value);
666 return this;
667 }
668 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800669 * This method will cause the View's <code>scaleX</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800670 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800671 *
672 * @param value The value to be animated to.
673 * @see View#setScaleX(float)
674 * @return This object, allowing calls to methods in this class to be chained.
675 */
676 public ViewPropertyAnimator scaleX(float value) {
677 animateProperty(SCALE_X, value);
678 return this;
679 }
680
681 /**
682 * This method will cause the View's <code>scaleX</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800683 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800684 *
685 * @param value The amount to be animated by, as an offset from the current value.
686 * @see View#setScaleX(float)
687 * @return This object, allowing calls to methods in this class to be chained.
688 */
689 public ViewPropertyAnimator scaleXBy(float value) {
690 animatePropertyBy(SCALE_X, value);
691 return this;
692 }
693
694 /**
695 * This method will cause the View's <code>scaleY</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800696 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800697 *
698 * @param value The value to be animated to.
699 * @see View#setScaleY(float)
700 * @return This object, allowing calls to methods in this class to be chained.
701 */
702 public ViewPropertyAnimator scaleY(float value) {
703 animateProperty(SCALE_Y, value);
704 return this;
705 }
706
707 /**
708 * This method will cause the View's <code>scaleY</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800709 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800710 *
711 * @param value The amount to be animated by, as an offset from the current value.
712 * @see View#setScaleY(float)
713 * @return This object, allowing calls to methods in this class to be chained.
714 */
715 public ViewPropertyAnimator scaleYBy(float value) {
716 animatePropertyBy(SCALE_Y, value);
717 return this;
718 }
719
720 /**
721 * This method will cause the View's <code>alpha</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800722 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800723 *
724 * @param value The value to be animated to.
725 * @see View#setAlpha(float)
726 * @return This object, allowing calls to methods in this class to be chained.
727 */
728 public ViewPropertyAnimator alpha(float value) {
729 animateProperty(ALPHA, value);
730 return this;
731 }
732
733 /**
734 * This method will cause the View's <code>alpha</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800735 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800736 *
737 * @param value The amount to be animated by, as an offset from the current value.
738 * @see View#setAlpha(float)
739 * @return This object, allowing calls to methods in this class to be chained.
740 */
741 public ViewPropertyAnimator alphaBy(float value) {
742 animatePropertyBy(ALPHA, value);
743 return this;
744 }
745
746 /**
Chet Haasec1ca6652012-01-31 07:33:48 -0800747 * The View associated with this ViewPropertyAnimator will have its
748 * {@link View#setLayerType(int, android.graphics.Paint) layer type} set to
Chet Haasecb150fe2012-05-03 15:15:05 -0700749 * {@link View#LAYER_TYPE_HARDWARE} for the duration of the next animation.
750 * As stated in the documentation for {@link View#LAYER_TYPE_HARDWARE},
751 * the actual type of layer used internally depends on the runtime situation of the
752 * view. If the activity and this view are hardware-accelerated, then the layer will be
753 * accelerated as well. If the activity or the view is not accelerated, then the layer will
754 * effectively be the same as {@link View#LAYER_TYPE_SOFTWARE}.
755 *
756 * <p>This state is not persistent, either on the View or on this ViewPropertyAnimator: the
757 * layer type of the View will be restored when the animation ends to what it was when this
758 * method was called, and this setting on ViewPropertyAnimator is only valid for the next
759 * animation. Note that calling this method and then independently setting the layer type of
760 * the View (by a direct call to {@link View#setLayerType(int, android.graphics.Paint)}) will
761 * result in some inconsistency, including having the layer type restored to its pre-withLayer()
762 * value when the animation ends.</p>
Chet Haasec1ca6652012-01-31 07:33:48 -0800763 *
764 * @see View#setLayerType(int, android.graphics.Paint)
765 * @return This object, allowing calls to methods in this class to be chained.
766 */
767 public ViewPropertyAnimator withLayer() {
768 mPendingSetupAction= new Runnable() {
769 @Override
770 public void run() {
771 mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
Chet Haase5fd37232013-09-13 19:01:52 -0700772 if (mView.isAttachedToWindow()) {
773 mView.buildLayer();
774 }
Chet Haasec1ca6652012-01-31 07:33:48 -0800775 }
776 };
777 final int currentLayerType = mView.getLayerType();
778 mPendingCleanupAction = new Runnable() {
779 @Override
780 public void run() {
781 mView.setLayerType(currentLayerType, null);
782 }
783 };
784 if (mAnimatorSetupMap == null) {
785 mAnimatorSetupMap = new HashMap<Animator, Runnable>();
786 }
787 if (mAnimatorCleanupMap == null) {
788 mAnimatorCleanupMap = new HashMap<Animator, Runnable>();
789 }
790
791 return this;
792 }
793
794 /**
795 * Specifies an action to take place when the next animation runs. If there is a
796 * {@link #setStartDelay(long) startDelay} set on this ViewPropertyAnimator, then the
797 * action will run after that startDelay expires, when the actual animation begins.
798 * This method, along with {@link #withEndAction(Runnable)}, is intended to help facilitate
799 * choreographing ViewPropertyAnimator animations with other animations or actions
800 * in the application.
801 *
802 * @param runnable The action to run when the next animation starts.
803 * @return This object, allowing calls to methods in this class to be chained.
804 */
805 public ViewPropertyAnimator withStartAction(Runnable runnable) {
806 mPendingOnStartAction = runnable;
807 if (runnable != null && mAnimatorOnStartMap == null) {
808 mAnimatorOnStartMap = new HashMap<Animator, Runnable>();
809 }
810 return this;
811 }
812
813 /**
814 * Specifies an action to take place when the next animation ends. The action is only
815 * run if the animation ends normally; if the ViewPropertyAnimator is canceled during
816 * that animation, the runnable will not run.
817 * This method, along with {@link #withStartAction(Runnable)}, is intended to help facilitate
818 * choreographing ViewPropertyAnimator animations with other animations or actions
819 * in the application.
820 *
821 * <p>For example, the following code animates a view to x=200 and then back to 0:</p>
822 * <pre>
823 * Runnable endAction = new Runnable() {
824 * public void run() {
825 * view.animate().x(0);
826 * }
827 * };
Robert Ly8ee2a702012-12-17 15:00:08 -0800828 * view.animate().x(200).withEndAction(endAction);
Chet Haasec1ca6652012-01-31 07:33:48 -0800829 * </pre>
830 *
831 * @param runnable The action to run when the next animation ends.
832 * @return This object, allowing calls to methods in this class to be chained.
833 */
834 public ViewPropertyAnimator withEndAction(Runnable runnable) {
835 mPendingOnEndAction = runnable;
836 if (runnable != null && mAnimatorOnEndMap == null) {
837 mAnimatorOnEndMap = new HashMap<Animator, Runnable>();
838 }
839 return this;
840 }
841
John Reck918988c2014-05-19 10:28:35 -0700842 boolean hasActions() {
843 return mPendingSetupAction != null
844 || mPendingCleanupAction != null
845 || mPendingOnStartAction != null
846 || mPendingOnEndAction != null;
847 }
848
Chet Haasec1ca6652012-01-31 07:33:48 -0800849 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800850 * Starts the underlying Animator for a set of properties. We use a single animator that
851 * simply runs from 0 to 1, and then use that fractional value to set each property
852 * value accordingly.
853 */
854 private void startAnimation() {
Chet Haase563d4f22012-04-18 16:20:08 -0700855 mView.setHasTransientState(true);
Chet Haasea00f3862011-02-22 06:34:40 -0800856 ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
857 ArrayList<NameValuesHolder> nameValueList =
858 (ArrayList<NameValuesHolder>) mPendingAnimations.clone();
859 mPendingAnimations.clear();
860 int propertyMask = 0;
861 int propertyCount = nameValueList.size();
862 for (int i = 0; i < propertyCount; ++i) {
863 NameValuesHolder nameValuesHolder = nameValueList.get(i);
864 propertyMask |= nameValuesHolder.mNameConstant;
865 }
Chet Haasea00f3862011-02-22 06:34:40 -0800866 mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
Chet Haasec1ca6652012-01-31 07:33:48 -0800867 if (mPendingSetupAction != null) {
868 mAnimatorSetupMap.put(animator, mPendingSetupAction);
869 mPendingSetupAction = null;
870 }
871 if (mPendingCleanupAction != null) {
872 mAnimatorCleanupMap.put(animator, mPendingCleanupAction);
873 mPendingCleanupAction = null;
874 }
875 if (mPendingOnStartAction != null) {
876 mAnimatorOnStartMap.put(animator, mPendingOnStartAction);
877 mPendingOnStartAction = null;
878 }
879 if (mPendingOnEndAction != null) {
880 mAnimatorOnEndMap.put(animator, mPendingOnEndAction);
881 mPendingOnEndAction = null;
882 }
Chet Haasea00f3862011-02-22 06:34:40 -0800883 animator.addUpdateListener(mAnimatorEventListener);
884 animator.addListener(mAnimatorEventListener);
Chet Haasecbbd93a2011-08-08 17:34:25 -0700885 if (mStartDelaySet) {
886 animator.setStartDelay(mStartDelay);
887 }
Chet Haasea00f3862011-02-22 06:34:40 -0800888 if (mDurationSet) {
889 animator.setDuration(mDuration);
890 }
Vladislav Kaznacheev78f146f2015-06-15 06:58:59 +0000891 if (mInterpolatorSet) {
Chet Haasea00f3862011-02-22 06:34:40 -0800892 animator.setInterpolator(mInterpolator);
893 }
894 animator.start();
895 }
896
897 /**
898 * Utility function, called by the various x(), y(), etc. methods. This stores the
Chet Haased666cf32011-03-01 07:31:30 -0800899 * constant name for the property along with the from/delta values that will be used to
Chet Haasea00f3862011-02-22 06:34:40 -0800900 * calculate and set the property during the animation. This structure is added to the
901 * pending animations, awaiting the eventual start() of the underlying animator. A
902 * Runnable is posted to start the animation, and any pending such Runnable is canceled
903 * (which enables us to end up starting just one animator for all of the properties
904 * specified at one time).
905 *
906 * @param constantName The specifier for the property being animated
907 * @param toValue The value to which the property will animate
908 */
909 private void animateProperty(int constantName, float toValue) {
910 float fromValue = getValue(constantName);
911 float deltaValue = toValue - fromValue;
912 animatePropertyBy(constantName, fromValue, deltaValue);
913 }
914
915 /**
916 * Utility function, called by the various xBy(), yBy(), etc. methods. This method is
917 * just like animateProperty(), except the value is an offset from the property's
918 * current value, instead of an absolute "to" value.
919 *
920 * @param constantName The specifier for the property being animated
921 * @param byValue The amount by which the property will change
922 */
923 private void animatePropertyBy(int constantName, float byValue) {
924 float fromValue = getValue(constantName);
925 animatePropertyBy(constantName, fromValue, byValue);
926 }
927
928 /**
Chet Haased666cf32011-03-01 07:31:30 -0800929 * Utility function, called by animateProperty() and animatePropertyBy(), which handles the
Chet Haasea00f3862011-02-22 06:34:40 -0800930 * details of adding a pending animation and posting the request to start the animation.
931 *
932 * @param constantName The specifier for the property being animated
Chet Haased666cf32011-03-01 07:31:30 -0800933 * @param startValue The starting value of the property
Chet Haasea00f3862011-02-22 06:34:40 -0800934 * @param byValue The amount by which the property will change
935 */
Chet Haased666cf32011-03-01 07:31:30 -0800936 private void animatePropertyBy(int constantName, float startValue, float byValue) {
Chet Haaseba592d202011-02-25 11:35:17 -0800937 // First, cancel any existing animations on this property
938 if (mAnimatorMap.size() > 0) {
939 Animator animatorToCancel = null;
940 Set<Animator> animatorSet = mAnimatorMap.keySet();
941 for (Animator runningAnim : animatorSet) {
942 PropertyBundle bundle = mAnimatorMap.get(runningAnim);
943 if (bundle.cancel(constantName)) {
944 // property was canceled - cancel the animation if it's now empty
945 // Note that it's safe to break out here because every new animation
946 // on a property will cancel a previous animation on that property, so
947 // there can only ever be one such animation running.
948 if (bundle.mPropertyMask == NONE) {
Chet Haase8d5f8082011-05-24 08:03:16 -0700949 // the animation is no longer changing anything - cancel it
Chet Haaseba592d202011-02-25 11:35:17 -0800950 animatorToCancel = runningAnim;
951 break;
952 }
953 }
954 }
955 if (animatorToCancel != null) {
956 animatorToCancel.cancel();
957 }
958 }
959
Chet Haasea00f3862011-02-22 06:34:40 -0800960 NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
961 mPendingAnimations.add(nameValuePair);
Chet Haase3a000a52011-06-16 13:55:11 -0700962 mView.removeCallbacks(mAnimationStarter);
Chet Haasedcfbd6a2013-05-09 14:40:21 -0700963 mView.postOnAnimation(mAnimationStarter);
Chet Haasea00f3862011-02-22 06:34:40 -0800964 }
965
966 /**
967 * This method handles setting the property values directly in the View object's fields.
968 * propertyConstant tells it which property should be set, value is the value to set
969 * the property to.
970 *
971 * @param propertyConstant The property to be set
972 * @param value The value to set the property to
973 */
974 private void setValue(int propertyConstant, float value) {
Chris Craik64a12e12014-03-28 18:12:12 -0700975 final RenderNode renderNode = mView.mRenderNode;
Chet Haasea00f3862011-02-22 06:34:40 -0800976 switch (propertyConstant) {
977 case TRANSLATION_X:
Chris Craik49e6c732014-03-31 12:34:11 -0700978 renderNode.setTranslationX(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800979 break;
980 case TRANSLATION_Y:
Chris Craik49e6c732014-03-31 12:34:11 -0700981 renderNode.setTranslationY(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800982 break;
Chris Craikf57776b2013-10-25 18:30:17 -0700983 case TRANSLATION_Z:
Chris Craik49e6c732014-03-31 12:34:11 -0700984 renderNode.setTranslationZ(value);
Chris Craikf57776b2013-10-25 18:30:17 -0700985 break;
Chet Haasea00f3862011-02-22 06:34:40 -0800986 case ROTATION:
John Recke57475e2019-02-20 17:39:52 -0800987 renderNode.setRotationZ(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800988 break;
989 case ROTATION_X:
Chris Craik49e6c732014-03-31 12:34:11 -0700990 renderNode.setRotationX(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800991 break;
992 case ROTATION_Y:
Chris Craik49e6c732014-03-31 12:34:11 -0700993 renderNode.setRotationY(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800994 break;
995 case SCALE_X:
Chris Craik49e6c732014-03-31 12:34:11 -0700996 renderNode.setScaleX(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800997 break;
998 case SCALE_Y:
Chris Craik49e6c732014-03-31 12:34:11 -0700999 renderNode.setScaleY(value);
Chet Haasea00f3862011-02-22 06:34:40 -08001000 break;
1001 case X:
Chris Craik49e6c732014-03-31 12:34:11 -07001002 renderNode.setTranslationX(value - mView.mLeft);
Chet Haasea00f3862011-02-22 06:34:40 -08001003 break;
1004 case Y:
Chris Craik49e6c732014-03-31 12:34:11 -07001005 renderNode.setTranslationY(value - mView.mTop);
Chet Haasea00f3862011-02-22 06:34:40 -08001006 break;
Chris Craikcc39e162014-04-25 18:34:11 -07001007 case Z:
1008 renderNode.setTranslationZ(value - renderNode.getElevation());
1009 break;
Chet Haasea00f3862011-02-22 06:34:40 -08001010 case ALPHA:
Qasid Ahmad Sadiq62058202019-05-16 01:19:29 -07001011 mView.setAlphaInternal(value);
Chris Craik49e6c732014-03-31 12:34:11 -07001012 renderNode.setAlpha(value);
Chet Haasea00f3862011-02-22 06:34:40 -08001013 break;
1014 }
1015 }
1016
1017 /**
1018 * This method gets the value of the named property from the View object.
1019 *
1020 * @param propertyConstant The property whose value should be returned
1021 * @return float The value of the named property
1022 */
1023 private float getValue(int propertyConstant) {
Chris Craik49e6c732014-03-31 12:34:11 -07001024 final RenderNode node = mView.mRenderNode;
Chet Haasea00f3862011-02-22 06:34:40 -08001025 switch (propertyConstant) {
1026 case TRANSLATION_X:
Chris Craik49e6c732014-03-31 12:34:11 -07001027 return node.getTranslationX();
Chet Haasea00f3862011-02-22 06:34:40 -08001028 case TRANSLATION_Y:
Chris Craik49e6c732014-03-31 12:34:11 -07001029 return node.getTranslationY();
Chris Craikf57776b2013-10-25 18:30:17 -07001030 case TRANSLATION_Z:
Chris Craik49e6c732014-03-31 12:34:11 -07001031 return node.getTranslationZ();
Chet Haasea00f3862011-02-22 06:34:40 -08001032 case ROTATION:
John Recke57475e2019-02-20 17:39:52 -08001033 return node.getRotationZ();
Chet Haasea00f3862011-02-22 06:34:40 -08001034 case ROTATION_X:
Chris Craik49e6c732014-03-31 12:34:11 -07001035 return node.getRotationX();
Chet Haasea00f3862011-02-22 06:34:40 -08001036 case ROTATION_Y:
Chris Craik49e6c732014-03-31 12:34:11 -07001037 return node.getRotationY();
Chet Haasea00f3862011-02-22 06:34:40 -08001038 case SCALE_X:
Chris Craik49e6c732014-03-31 12:34:11 -07001039 return node.getScaleX();
Chet Haasea00f3862011-02-22 06:34:40 -08001040 case SCALE_Y:
Chris Craik49e6c732014-03-31 12:34:11 -07001041 return node.getScaleY();
Chet Haasea00f3862011-02-22 06:34:40 -08001042 case X:
Chris Craik49e6c732014-03-31 12:34:11 -07001043 return mView.mLeft + node.getTranslationX();
Chet Haasea00f3862011-02-22 06:34:40 -08001044 case Y:
Chris Craik49e6c732014-03-31 12:34:11 -07001045 return mView.mTop + node.getTranslationY();
Chris Craikcc39e162014-04-25 18:34:11 -07001046 case Z:
1047 return node.getElevation() + node.getTranslationZ();
Chet Haasea00f3862011-02-22 06:34:40 -08001048 case ALPHA:
Qasid Ahmad Sadiq62058202019-05-16 01:19:29 -07001049 return mView.getAlpha();
Chet Haasea00f3862011-02-22 06:34:40 -08001050 }
1051 return 0;
1052 }
1053
1054 /**
1055 * Utility class that handles the various Animator events. The only ones we care
1056 * about are the end event (which we use to clean up the animator map when an animator
1057 * finishes) and the update event (which we use to calculate the current value of each
1058 * property and then set it on the view object).
1059 */
1060 private class AnimatorEventListener
1061 implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
1062 @Override
1063 public void onAnimationStart(Animator animation) {
Chet Haasec1ca6652012-01-31 07:33:48 -08001064 if (mAnimatorSetupMap != null) {
1065 Runnable r = mAnimatorSetupMap.get(animation);
1066 if (r != null) {
1067 r.run();
1068 }
1069 mAnimatorSetupMap.remove(animation);
1070 }
1071 if (mAnimatorOnStartMap != null) {
1072 Runnable r = mAnimatorOnStartMap.get(animation);
1073 if (r != null) {
1074 r.run();
1075 }
1076 mAnimatorOnStartMap.remove(animation);
1077 }
Chet Haasea00f3862011-02-22 06:34:40 -08001078 if (mListener != null) {
1079 mListener.onAnimationStart(animation);
1080 }
1081 }
1082
1083 @Override
1084 public void onAnimationCancel(Animator animation) {
1085 if (mListener != null) {
1086 mListener.onAnimationCancel(animation);
1087 }
Chet Haasec1ca6652012-01-31 07:33:48 -08001088 if (mAnimatorOnEndMap != null) {
1089 mAnimatorOnEndMap.remove(animation);
1090 }
Chet Haasea00f3862011-02-22 06:34:40 -08001091 }
1092
1093 @Override
1094 public void onAnimationRepeat(Animator animation) {
1095 if (mListener != null) {
1096 mListener.onAnimationRepeat(animation);
1097 }
1098 }
1099
1100 @Override
1101 public void onAnimationEnd(Animator animation) {
Chet Haase563d4f22012-04-18 16:20:08 -07001102 mView.setHasTransientState(false);
George Mountf643fb02016-03-31 15:45:35 +00001103 if (mAnimatorCleanupMap != null) {
1104 Runnable r = mAnimatorCleanupMap.get(animation);
1105 if (r != null) {
1106 r.run();
1107 }
1108 mAnimatorCleanupMap.remove(animation);
1109 }
Chet Haasea00f3862011-02-22 06:34:40 -08001110 if (mListener != null) {
1111 mListener.onAnimationEnd(animation);
1112 }
George Mounte9a4f872016-03-29 07:39:02 -07001113 if (mAnimatorOnEndMap != null) {
1114 Runnable r = mAnimatorOnEndMap.get(animation);
1115 if (r != null) {
1116 r.run();
1117 }
1118 mAnimatorOnEndMap.remove(animation);
1119 }
Chet Haasea00f3862011-02-22 06:34:40 -08001120 mAnimatorMap.remove(animation);
1121 }
1122
1123 /**
1124 * Calculate the current value for each property and set it on the view. Invalidate
1125 * the view object appropriately, depending on which properties are being animated.
1126 *
1127 * @param animation The animator associated with the properties that need to be
1128 * set. This animator holds the animation fraction which we will use to calculate
1129 * the current value of each property.
1130 */
1131 @Override
1132 public void onAnimationUpdate(ValueAnimator animation) {
Chet Haase0c6d83cc2011-12-01 08:38:13 -08001133 PropertyBundle propertyBundle = mAnimatorMap.get(animation);
1134 if (propertyBundle == null) {
1135 // Shouldn't happen, but just to play it safe
1136 return;
1137 }
Chris Craik30485452014-05-27 19:18:10 -07001138
1139 boolean hardwareAccelerated = mView.isHardwareAccelerated();
Chet Haase9d1992d2012-03-13 11:03:25 -07001140
Nader Jawad6fa971b2019-09-16 16:46:25 -07001141 // alpha requires slightly different treatment than the other (transform) properties.
1142 // The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
1143 // logic is dependent on how the view handles an internal call to onSetAlpha().
1144 // We track what kinds of properties are set, and how alpha is handled when it is
1145 // set, and perform the invalidation steps appropriately.
1146 boolean alphaHandled = false;
Chris Craik30485452014-05-27 19:18:10 -07001147 if (!hardwareAccelerated) {
Chet Haase9d1992d2012-03-13 11:03:25 -07001148 mView.invalidateParentCaches();
1149 }
Chet Haasea00f3862011-02-22 06:34:40 -08001150 float fraction = animation.getAnimatedFraction();
Chet Haasea00f3862011-02-22 06:34:40 -08001151 int propertyMask = propertyBundle.mPropertyMask;
1152 if ((propertyMask & TRANSFORM_MASK) != 0) {
Chris Craik30485452014-05-27 19:18:10 -07001153 mView.invalidateViewProperty(hardwareAccelerated, false);
Chet Haasea00f3862011-02-22 06:34:40 -08001154 }
1155 ArrayList<NameValuesHolder> valueList = propertyBundle.mNameValuesHolder;
1156 if (valueList != null) {
1157 int count = valueList.size();
1158 for (int i = 0; i < count; ++i) {
1159 NameValuesHolder values = valueList.get(i);
1160 float value = values.mFromValue + fraction * values.mDeltaValue;
Nader Jawad6fa971b2019-09-16 16:46:25 -07001161 if (values.mNameConstant == ALPHA) {
1162 alphaHandled = mView.setAlphaNoInvalidation(value);
1163 } else {
1164 setValue(values.mNameConstant, value);
1165 }
Chet Haasea00f3862011-02-22 06:34:40 -08001166 }
1167 }
1168 if ((propertyMask & TRANSFORM_MASK) != 0) {
Chris Craik30485452014-05-27 19:18:10 -07001169 if (!hardwareAccelerated) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001170 mView.mPrivateFlags |= View.PFLAG_DRAWN; // force another invalidation
Chet Haase9d1992d2012-03-13 11:03:25 -07001171 }
Chet Haasea00f3862011-02-22 06:34:40 -08001172 }
Nader Jawad6fa971b2019-09-16 16:46:25 -07001173 // invalidate(false) in all cases except if alphaHandled gets set to true
1174 // via the call to setAlphaNoInvalidation(), above
1175 if (alphaHandled) {
1176 mView.invalidate(true);
1177 } else {
1178 mView.invalidateViewProperty(false, false);
1179 }
Chet Haase87f4ae62013-09-06 18:29:56 -07001180 if (mUpdateListener != null) {
1181 mUpdateListener.onAnimationUpdate(animation);
1182 }
Chet Haasea00f3862011-02-22 06:34:40 -08001183 }
1184 }
1185}