blob: 6c84b63bb2414fa689b90794fbeaac295c652da5 [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;
22
Chet Haasea00f3862011-02-22 06:34:40 -080023import java.util.ArrayList;
24import java.util.HashMap;
25import java.util.Set;
26
27/**
28 * This class enables automatic and optimized animation of select properties on View objects.
29 * If only one or two properties on a View object are being animated, then using an
30 * {@link android.animation.ObjectAnimator} is fine; the property setters called by ObjectAnimator
31 * are well equipped to do the right thing to set the property and invalidate the view
32 * appropriately. But if several properties are animated simultaneously, or if you just want a
33 * more convenient syntax to animate a specific property, then ViewPropertyAnimator might be
34 * more well-suited to the task.
35 *
Chet Haased666cf32011-03-01 07:31:30 -080036 * <p>This class may provide better performance for several simultaneous animations, because
37 * it will optimize invalidate calls to take place only once for several properties instead of each
38 * animated property independently causing its own invalidation. Also, the syntax of using this
Chet Haasea00f3862011-02-22 06:34:40 -080039 * class could be easier to use because the caller need only tell the View object which
Chet Haased666cf32011-03-01 07:31:30 -080040 * property to animate, and the value to animate either to or by, and this class handles the
Chet Haasea00f3862011-02-22 06:34:40 -080041 * details of configuring the underlying Animator class and starting it.</p>
42 *
43 * <p>This class is not constructed by the caller, but rather by the View whose properties
44 * it will animate. Calls to {@link android.view.View#animate()} will return a reference
45 * to the appropriate ViewPropertyAnimator object for that View.</p>
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -070046 *
Chet Haasea00f3862011-02-22 06:34:40 -080047 */
48public class ViewPropertyAnimator {
49
50 /**
51 * The View whose properties are being animated by this class. This is set at
52 * construction time.
53 */
John Reck44244ff2014-06-20 14:44:58 -070054 final View mView;
Chet Haasea00f3862011-02-22 06:34:40 -080055
56 /**
57 * The duration of the underlying Animator object. By default, we don't set the duration
58 * on the Animator and just use its default duration. If the duration is ever set on this
59 * Animator, then we use the duration that it was set to.
60 */
61 private long mDuration;
62
63 /**
64 * A flag indicating whether the duration has been set on this object. If not, we don't set
65 * the duration on the underlying Animator, but instead just use its default duration.
66 */
67 private boolean mDurationSet = false;
68
69 /**
Chet Haase8d5f8082011-05-24 08:03:16 -070070 * The startDelay of the underlying Animator object. By default, we don't set the startDelay
71 * on the Animator and just use its default startDelay. If the startDelay is ever set on this
72 * Animator, then we use the startDelay that it was set to.
73 */
74 private long mStartDelay = 0;
75
76 /**
77 * A flag indicating whether the startDelay has been set on this object. If not, we don't set
78 * the startDelay on the underlying Animator, but instead just use its default startDelay.
79 */
80 private boolean mStartDelaySet = false;
81
82 /**
Chet Haasea00f3862011-02-22 06:34:40 -080083 * The interpolator of the underlying Animator object. By default, we don't set the interpolator
Vladislav Kaznacheev78f146f2015-06-15 06:58:59 +000084 * on the Animator and just use its default interpolator. If the interpolator is ever set on
85 * this Animator, then we use the interpolator that it was set to.
Chet Haasea00f3862011-02-22 06:34:40 -080086 */
87 private TimeInterpolator mInterpolator;
88
89 /**
Vladislav Kaznacheev78f146f2015-06-15 06:58:59 +000090 * A flag indicating whether the interpolator has been set on this object. If not, we don't set
91 * the interpolator on the underlying Animator, but instead just use its default interpolator.
92 */
93 private boolean mInterpolatorSet = false;
94
95 /**
Chet Haase87f4ae62013-09-06 18:29:56 -070096 * Listener for the lifecycle events of the underlying ValueAnimator object.
Chet Haasea00f3862011-02-22 06:34:40 -080097 */
98 private Animator.AnimatorListener mListener = null;
99
100 /**
Chet Haase87f4ae62013-09-06 18:29:56 -0700101 * Listener for the update events of the underlying ValueAnimator object.
102 */
103 private ValueAnimator.AnimatorUpdateListener mUpdateListener = null;
104
105 /**
Cyril Mottierd40acfb2013-07-25 10:08:29 +0200106 * A lazily-created ValueAnimator used in order to get some default animator properties
107 * (duration, start delay, interpolator, etc.).
108 */
109 private ValueAnimator mTempValueAnimator;
110
111 /**
John Reck918988c2014-05-19 10:28:35 -0700112 * A RenderThread-driven backend that may intercept startAnimation
113 */
114 private ViewPropertyAnimatorRT mRTBackend;
115
116 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800117 * This listener is the mechanism by which the underlying Animator causes changes to the
118 * properties currently being animated, as well as the cleanup after an animation is
119 * complete.
120 */
121 private AnimatorEventListener mAnimatorEventListener = new AnimatorEventListener();
122
123 /**
124 * This list holds the properties that have been asked to animate. We allow the caller to
125 * request several animations prior to actually starting the underlying animator. This
126 * enables us to run one single animator to handle several properties in parallel. Each
127 * property is tossed onto the pending list until the animation actually starts (which is
128 * done by posting it onto mView), at which time the pending list is cleared and the properties
129 * on that list are added to the list of properties associated with that animator.
130 */
131 ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();
Chet Haasec1ca6652012-01-31 07:33:48 -0800132 private Runnable mPendingSetupAction;
133 private Runnable mPendingCleanupAction;
134 private Runnable mPendingOnStartAction;
135 private Runnable mPendingOnEndAction;
Chet Haasea00f3862011-02-22 06:34:40 -0800136
137 /**
138 * Constants used to associate a property being requested and the mechanism used to set
Chet Haased666cf32011-03-01 07:31:30 -0800139 * the property (this class calls directly into View to set the properties in question).
Chet Haasea00f3862011-02-22 06:34:40 -0800140 */
John Recke45b1fd2014-04-15 09:50:16 -0700141 static final int NONE = 0x0000;
142 static final int TRANSLATION_X = 0x0001;
143 static final int TRANSLATION_Y = 0x0002;
144 static final int TRANSLATION_Z = 0x0004;
145 static final int SCALE_X = 0x0008;
146 static final int SCALE_Y = 0x0010;
147 static final int ROTATION = 0x0020;
148 static final int ROTATION_X = 0x0040;
149 static final int ROTATION_Y = 0x0080;
150 static final int X = 0x0100;
151 static final int Y = 0x0200;
152 static final int Z = 0x0400;
153 static final int ALPHA = 0x0800;
Chet Haasea00f3862011-02-22 06:34:40 -0800154
Chris Craikf57776b2013-10-25 18:30:17 -0700155 private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | TRANSLATION_Z |
Chris Craikcc39e162014-04-25 18:34:11 -0700156 SCALE_X | SCALE_Y | ROTATION | ROTATION_X | ROTATION_Y | X | Y | Z;
Chet Haasea00f3862011-02-22 06:34:40 -0800157
158 /**
159 * The mechanism by which the user can request several properties that are then animated
160 * together works by posting this Runnable to start the underlying Animator. Every time
161 * a property animation is requested, we cancel any previous postings of the Runnable
162 * and re-post it. This means that we will only ever run the Runnable (and thus start the
163 * underlying animator) after the caller is done setting the properties that should be
164 * animated together.
165 */
166 private Runnable mAnimationStarter = new Runnable() {
167 @Override
168 public void run() {
169 startAnimation();
170 }
171 };
172
173 /**
174 * This class holds information about the overall animation being run on the set of
175 * properties. The mask describes which properties are being animated and the
176 * values holder is the list of all property/value objects.
177 */
178 private static class PropertyBundle {
179 int mPropertyMask;
180 ArrayList<NameValuesHolder> mNameValuesHolder;
Chet Haaseba592d202011-02-25 11:35:17 -0800181
Chet Haasea00f3862011-02-22 06:34:40 -0800182 PropertyBundle(int propertyMask, ArrayList<NameValuesHolder> nameValuesHolder) {
183 mPropertyMask = propertyMask;
184 mNameValuesHolder = nameValuesHolder;
185 }
Chet Haaseba592d202011-02-25 11:35:17 -0800186
187 /**
188 * Removes the given property from being animated as a part of this
189 * PropertyBundle. If the property was a part of this bundle, it returns
190 * true to indicate that it was, in fact, canceled. This is an indication
191 * to the caller that a cancellation actually occurred.
192 *
193 * @param propertyConstant The property whose cancellation is requested.
194 * @return true if the given property is a part of this bundle and if it
195 * has therefore been canceled.
196 */
197 boolean cancel(int propertyConstant) {
198 if ((mPropertyMask & propertyConstant) != 0 && mNameValuesHolder != null) {
199 int count = mNameValuesHolder.size();
200 for (int i = 0; i < count; ++i) {
201 NameValuesHolder nameValuesHolder = mNameValuesHolder.get(i);
202 if (nameValuesHolder.mNameConstant == propertyConstant) {
203 mNameValuesHolder.remove(i);
204 mPropertyMask &= ~propertyConstant;
205 return true;
206 }
207 }
208 }
209 return false;
210 }
Chet Haasea00f3862011-02-22 06:34:40 -0800211 }
212
213 /**
214 * This list tracks the list of properties being animated by any particular animator.
215 * In most situations, there would only ever be one animator running at a time. But it is
216 * possible to request some properties to animate together, then while those properties
217 * are animating, to request some other properties to animate together. The way that
218 * works is by having this map associate the group of properties being animated with the
219 * animator handling the animation. On every update event for an Animator, we ask the
220 * map for the associated properties and set them accordingly.
221 */
222 private HashMap<Animator, PropertyBundle> mAnimatorMap =
223 new HashMap<Animator, PropertyBundle>();
Chet Haasec1ca6652012-01-31 07:33:48 -0800224 private HashMap<Animator, Runnable> mAnimatorSetupMap;
225 private HashMap<Animator, Runnable> mAnimatorCleanupMap;
226 private HashMap<Animator, Runnable> mAnimatorOnStartMap;
227 private HashMap<Animator, Runnable> mAnimatorOnEndMap;
Chet Haasea00f3862011-02-22 06:34:40 -0800228
229 /**
230 * This is the information we need to set each property during the animation.
231 * mNameConstant is used to set the appropriate field in View, and the from/delta
232 * values are used to calculate the animated value for a given animation fraction
233 * during the animation.
234 */
John Reck918988c2014-05-19 10:28:35 -0700235 static class NameValuesHolder {
Chet Haasea00f3862011-02-22 06:34:40 -0800236 int mNameConstant;
237 float mFromValue;
238 float mDeltaValue;
239 NameValuesHolder(int nameConstant, float fromValue, float deltaValue) {
240 mNameConstant = nameConstant;
241 mFromValue = fromValue;
242 mDeltaValue = deltaValue;
243 }
244 }
245
246 /**
247 * Constructor, called by View. This is private by design, as the user should only
248 * get a ViewPropertyAnimator by calling View.animate().
249 *
250 * @param view The View associated with this ViewPropertyAnimator
251 */
252 ViewPropertyAnimator(View view) {
253 mView = view;
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700254 view.ensureTransformationInfo();
Chet Haasea00f3862011-02-22 06:34:40 -0800255 }
256
257 /**
258 * Sets the duration for the underlying animator that animates the requested properties.
259 * By default, the animator uses the default value for ValueAnimator. Calling this method
260 * will cause the declared value to be used instead.
261 * @param duration The length of ensuing property animations, in milliseconds. The value
262 * cannot be negative.
263 * @return This object, allowing calls to methods in this class to be chained.
264 */
265 public ViewPropertyAnimator setDuration(long duration) {
266 if (duration < 0) {
267 throw new IllegalArgumentException("Animators cannot have negative duration: " +
268 duration);
269 }
270 mDurationSet = true;
271 mDuration = duration;
272 return this;
273 }
274
275 /**
Chet Haase8d5f8082011-05-24 08:03:16 -0700276 * Returns the current duration of property animations. If the duration was set on this
277 * object, that value is returned. Otherwise, the default value of the underlying Animator
278 * is returned.
279 *
280 * @see #setDuration(long)
281 * @return The duration of animations, in milliseconds.
282 */
283 public long getDuration() {
Chet Haasecbbd93a2011-08-08 17:34:25 -0700284 if (mDurationSet) {
285 return mDuration;
Chet Haase8d5f8082011-05-24 08:03:16 -0700286 } else {
287 // Just return the default from ValueAnimator, since that's what we'd get if
288 // the value has not been set otherwise
Cyril Mottierd40acfb2013-07-25 10:08:29 +0200289 if (mTempValueAnimator == null) {
290 mTempValueAnimator = new ValueAnimator();
291 }
292 return mTempValueAnimator.getDuration();
Chet Haase8d5f8082011-05-24 08:03:16 -0700293 }
294 }
295
296 /**
297 * Returns the current startDelay of property animations. If the startDelay was set on this
298 * object, that value is returned. Otherwise, the default value of the underlying Animator
299 * is returned.
300 *
301 * @see #setStartDelay(long)
302 * @return The startDelay of animations, in milliseconds.
303 */
304 public long getStartDelay() {
305 if (mStartDelaySet) {
306 return mStartDelay;
307 } else {
308 // Just return the default from ValueAnimator (0), since that's what we'd get if
309 // the value has not been set otherwise
310 return 0;
311 }
312 }
313
314 /**
315 * Sets the startDelay for the underlying animator that animates the requested properties.
316 * By default, the animator uses the default value for ValueAnimator. Calling this method
317 * will cause the declared value to be used instead.
318 * @param startDelay The delay of ensuing property animations, in milliseconds. The value
319 * cannot be negative.
320 * @return This object, allowing calls to methods in this class to be chained.
321 */
322 public ViewPropertyAnimator setStartDelay(long startDelay) {
323 if (startDelay < 0) {
Cyril Mottier772bafa2013-10-02 16:57:57 +0200324 throw new IllegalArgumentException("Animators cannot have negative start " +
325 "delay: " + startDelay);
Chet Haase8d5f8082011-05-24 08:03:16 -0700326 }
327 mStartDelaySet = true;
328 mStartDelay = startDelay;
329 return this;
330 }
331
332 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800333 * Sets the interpolator for the underlying animator that animates the requested properties.
334 * By default, the animator uses the default interpolator for ValueAnimator. Calling this method
335 * will cause the declared object to be used instead.
Aurimas Liutikas67e2ae82016-10-11 18:17:42 -0700336 *
John Recka0b13bd2014-07-01 08:34:47 -0700337 * @param interpolator The TimeInterpolator to be used for ensuing property animations. A value
338 * of <code>null</code> will result in linear interpolation.
Chet Haasea00f3862011-02-22 06:34:40 -0800339 * @return This object, allowing calls to methods in this class to be chained.
340 */
341 public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) {
Vladislav Kaznacheev78f146f2015-06-15 06:58:59 +0000342 mInterpolatorSet = true;
Chet Haasea00f3862011-02-22 06:34:40 -0800343 mInterpolator = interpolator;
344 return this;
345 }
346
347 /**
Chet Haase430742f2013-04-12 11:18:36 -0700348 * Returns the timing interpolator that this animation uses.
349 *
350 * @return The timing interpolator for this animation.
351 */
352 public TimeInterpolator getInterpolator() {
Vladislav Kaznacheev78f146f2015-06-15 06:58:59 +0000353 if (mInterpolatorSet) {
Cyril Mottierd40acfb2013-07-25 10:08:29 +0200354 return mInterpolator;
355 } else {
356 // Just return the default from ValueAnimator, since that's what we'd get if
357 // the value has not been set otherwise
358 if (mTempValueAnimator == null) {
359 mTempValueAnimator = new ValueAnimator();
360 }
361 return mTempValueAnimator.getInterpolator();
362 }
Chet Haase430742f2013-04-12 11:18:36 -0700363 }
364
365 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800366 * Sets a listener for events in the underlying Animators that run the property
367 * animations.
368 *
Chet Haase87f4ae62013-09-06 18:29:56 -0700369 * @see Animator.AnimatorListener
370 *
371 * @param listener The listener to be called with AnimatorListener events. A value of
372 * <code>null</code> removes any existing listener.
Chet Haasea00f3862011-02-22 06:34:40 -0800373 * @return This object, allowing calls to methods in this class to be chained.
374 */
375 public ViewPropertyAnimator setListener(Animator.AnimatorListener listener) {
376 mListener = listener;
377 return this;
378 }
379
John Reck918988c2014-05-19 10:28:35 -0700380 Animator.AnimatorListener getListener() {
381 return mListener;
382 }
383
Chet Haasea00f3862011-02-22 06:34:40 -0800384 /**
Chet Haase87f4ae62013-09-06 18:29:56 -0700385 * Sets a listener for update events in the underlying ValueAnimator that runs
386 * the property animations. Note that the underlying animator is animating between
387 * 0 and 1 (these values are then turned into the actual property values internally
388 * by ViewPropertyAnimator). So the animator cannot give information on the current
389 * values of the properties being animated by this ViewPropertyAnimator, although
390 * the view object itself can be queried to get the current values.
391 *
392 * @see android.animation.ValueAnimator.AnimatorUpdateListener
393 *
394 * @param listener The listener to be called with update events. A value of
395 * <code>null</code> removes any existing listener.
396 * @return This object, allowing calls to methods in this class to be chained.
397 */
398 public ViewPropertyAnimator setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) {
399 mUpdateListener = listener;
400 return this;
401 }
402
John Reck918988c2014-05-19 10:28:35 -0700403 ValueAnimator.AnimatorUpdateListener getUpdateListener() {
404 return mUpdateListener;
405 }
406
Chet Haase87f4ae62013-09-06 18:29:56 -0700407 /**
Chet Haase8d5f8082011-05-24 08:03:16 -0700408 * Starts the currently pending property animations immediately. Calling <code>start()</code>
409 * is optional because all animations start automatically at the next opportunity. However,
410 * if the animations are needed to start immediately and synchronously (not at the time when
411 * the next event is processed by the hierarchy, which is when the animations would begin
412 * otherwise), then this method can be used.
413 */
414 public void start() {
Michael Jurka500998d2012-05-13 15:35:02 -0700415 mView.removeCallbacks(mAnimationStarter);
Chet Haase8d5f8082011-05-24 08:03:16 -0700416 startAnimation();
417 }
418
419 /**
420 * Cancels all property animations that are currently running or pending.
421 */
422 public void cancel() {
423 if (mAnimatorMap.size() > 0) {
424 HashMap<Animator, PropertyBundle> mAnimatorMapCopy =
425 (HashMap<Animator, PropertyBundle>)mAnimatorMap.clone();
426 Set<Animator> animatorSet = mAnimatorMapCopy.keySet();
427 for (Animator runningAnim : animatorSet) {
428 runningAnim.cancel();
429 }
430 }
431 mPendingAnimations.clear();
Chet Haase5637b7d2014-08-28 07:53:59 -0700432 mPendingSetupAction = null;
433 mPendingCleanupAction = null;
434 mPendingOnStartAction = null;
435 mPendingOnEndAction = null;
Chet Haase3a000a52011-06-16 13:55:11 -0700436 mView.removeCallbacks(mAnimationStarter);
John Reck22184722014-06-20 07:19:30 -0700437 if (mRTBackend != null) {
438 mRTBackend.cancelAll();
439 }
Chet Haase8d5f8082011-05-24 08:03:16 -0700440 }
441
442 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800443 * This method will cause the View's <code>x</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800444 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800445 *
446 * @param value The value to be animated to.
447 * @see View#setX(float)
448 * @return This object, allowing calls to methods in this class to be chained.
449 */
450 public ViewPropertyAnimator x(float value) {
451 animateProperty(X, value);
452 return this;
453 }
454
455 /**
456 * This method will cause the View's <code>x</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800457 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800458 *
459 * @param value The amount to be animated by, as an offset from the current value.
460 * @see View#setX(float)
461 * @return This object, allowing calls to methods in this class to be chained.
462 */
463 public ViewPropertyAnimator xBy(float value) {
464 animatePropertyBy(X, value);
465 return this;
466 }
467
468 /**
469 * This method will cause the View's <code>y</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800470 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800471 *
472 * @param value The value to be animated to.
473 * @see View#setY(float)
474 * @return This object, allowing calls to methods in this class to be chained.
475 */
476 public ViewPropertyAnimator y(float value) {
477 animateProperty(Y, value);
478 return this;
479 }
480
481 /**
482 * This method will cause the View's <code>y</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800483 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800484 *
485 * @param value The amount to be animated by, as an offset from the current value.
486 * @see View#setY(float)
487 * @return This object, allowing calls to methods in this class to be chained.
488 */
489 public ViewPropertyAnimator yBy(float value) {
490 animatePropertyBy(Y, value);
491 return this;
492 }
493
494 /**
Chris Craikcc39e162014-04-25 18:34:11 -0700495 * This method will cause the View's <code>z</code> property to be animated to the
496 * specified value. Animations already running on the property will be canceled.
497 *
498 * @param value The value to be animated to.
499 * @see View#setZ(float)
500 * @return This object, allowing calls to methods in this class to be chained.
501 */
502 public ViewPropertyAnimator z(float value) {
503 animateProperty(Z, value);
504 return this;
505 }
506
507 /**
508 * This method will cause the View's <code>z</code> property to be animated by the
509 * specified value. Animations already running on the property will be canceled.
510 *
511 * @param value The amount to be animated by, as an offset from the current value.
512 * @see View#setZ(float)
513 * @return This object, allowing calls to methods in this class to be chained.
514 */
515 public ViewPropertyAnimator zBy(float value) {
516 animatePropertyBy(Z, value);
517 return this;
518 }
519
520 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800521 * This method will cause the View's <code>rotation</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800522 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800523 *
524 * @param value The value to be animated to.
525 * @see View#setRotation(float)
526 * @return This object, allowing calls to methods in this class to be chained.
527 */
528 public ViewPropertyAnimator rotation(float value) {
529 animateProperty(ROTATION, value);
530 return this;
531 }
532
533 /**
534 * This method will cause the View's <code>rotation</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800535 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800536 *
537 * @param value The amount to be animated by, as an offset from the current value.
538 * @see View#setRotation(float)
539 * @return This object, allowing calls to methods in this class to be chained.
540 */
541 public ViewPropertyAnimator rotationBy(float value) {
542 animatePropertyBy(ROTATION, value);
543 return this;
544 }
545
546 /**
547 * This method will cause the View's <code>rotationX</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800548 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800549 *
550 * @param value The value to be animated to.
551 * @see View#setRotationX(float)
552 * @return This object, allowing calls to methods in this class to be chained.
553 */
554 public ViewPropertyAnimator rotationX(float value) {
555 animateProperty(ROTATION_X, value);
556 return this;
557 }
558
559 /**
560 * This method will cause the View's <code>rotationX</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800561 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800562 *
563 * @param value The amount to be animated by, as an offset from the current value.
564 * @see View#setRotationX(float)
565 * @return This object, allowing calls to methods in this class to be chained.
566 */
567 public ViewPropertyAnimator rotationXBy(float value) {
568 animatePropertyBy(ROTATION_X, value);
569 return this;
570 }
571
572 /**
573 * This method will cause the View's <code>rotationY</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800574 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800575 *
576 * @param value The value to be animated to.
577 * @see View#setRotationY(float)
578 * @return This object, allowing calls to methods in this class to be chained.
579 */
580 public ViewPropertyAnimator rotationY(float value) {
581 animateProperty(ROTATION_Y, value);
582 return this;
583 }
584
585 /**
586 * This method will cause the View's <code>rotationY</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800587 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800588 *
589 * @param value The amount to be animated by, as an offset from the current value.
590 * @see View#setRotationY(float)
591 * @return This object, allowing calls to methods in this class to be chained.
592 */
593 public ViewPropertyAnimator rotationYBy(float value) {
594 animatePropertyBy(ROTATION_Y, value);
595 return this;
596 }
597
598 /**
599 * This method will cause the View's <code>translationX</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800600 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800601 *
602 * @param value The value to be animated to.
603 * @see View#setTranslationX(float)
604 * @return This object, allowing calls to methods in this class to be chained.
605 */
606 public ViewPropertyAnimator translationX(float value) {
607 animateProperty(TRANSLATION_X, value);
608 return this;
609 }
610
611 /**
612 * This method will cause the View's <code>translationX</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800613 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800614 *
615 * @param value The amount to be animated by, as an offset from the current value.
616 * @see View#setTranslationX(float)
617 * @return This object, allowing calls to methods in this class to be chained.
618 */
619 public ViewPropertyAnimator translationXBy(float value) {
620 animatePropertyBy(TRANSLATION_X, value);
621 return this;
622 }
623
624 /**
625 * This method will cause the View's <code>translationY</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800626 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800627 *
628 * @param value The value to be animated to.
629 * @see View#setTranslationY(float)
630 * @return This object, allowing calls to methods in this class to be chained.
631 */
632 public ViewPropertyAnimator translationY(float value) {
633 animateProperty(TRANSLATION_Y, value);
634 return this;
635 }
636
637 /**
638 * This method will cause the View's <code>translationY</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800639 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800640 *
641 * @param value The amount to be animated by, as an offset from the current value.
642 * @see View#setTranslationY(float)
643 * @return This object, allowing calls to methods in this class to be chained.
644 */
645 public ViewPropertyAnimator translationYBy(float value) {
646 animatePropertyBy(TRANSLATION_Y, value);
647 return this;
648 }
649
650 /**
Chris Craikd863a102013-12-19 13:31:15 -0800651 * This method will cause the View's <code>translationZ</code> property to be animated to the
652 * specified value. Animations already running on the property will be canceled.
653 *
654 * @param value The value to be animated to.
655 * @see View#setTranslationZ(float)
656 * @return This object, allowing calls to methods in this class to be chained.
657 */
658 public ViewPropertyAnimator translationZ(float value) {
659 animateProperty(TRANSLATION_Z, value);
660 return this;
661 }
662
663 /**
664 * This method will cause the View's <code>translationZ</code> property to be animated by the
665 * specified value. Animations already running on the property will be canceled.
666 *
667 * @param value The amount to be animated by, as an offset from the current value.
668 * @see View#setTranslationZ(float)
669 * @return This object, allowing calls to methods in this class to be chained.
670 */
671 public ViewPropertyAnimator translationZBy(float value) {
672 animatePropertyBy(TRANSLATION_Z, value);
673 return this;
674 }
675 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800676 * This method will cause the View's <code>scaleX</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800677 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800678 *
679 * @param value The value to be animated to.
680 * @see View#setScaleX(float)
681 * @return This object, allowing calls to methods in this class to be chained.
682 */
683 public ViewPropertyAnimator scaleX(float value) {
684 animateProperty(SCALE_X, value);
685 return this;
686 }
687
688 /**
689 * This method will cause the View's <code>scaleX</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800690 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800691 *
692 * @param value The amount to be animated by, as an offset from the current value.
693 * @see View#setScaleX(float)
694 * @return This object, allowing calls to methods in this class to be chained.
695 */
696 public ViewPropertyAnimator scaleXBy(float value) {
697 animatePropertyBy(SCALE_X, value);
698 return this;
699 }
700
701 /**
702 * This method will cause the View's <code>scaleY</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800703 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800704 *
705 * @param value The value to be animated to.
706 * @see View#setScaleY(float)
707 * @return This object, allowing calls to methods in this class to be chained.
708 */
709 public ViewPropertyAnimator scaleY(float value) {
710 animateProperty(SCALE_Y, value);
711 return this;
712 }
713
714 /**
715 * This method will cause the View's <code>scaleY</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800716 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800717 *
718 * @param value The amount to be animated by, as an offset from the current value.
719 * @see View#setScaleY(float)
720 * @return This object, allowing calls to methods in this class to be chained.
721 */
722 public ViewPropertyAnimator scaleYBy(float value) {
723 animatePropertyBy(SCALE_Y, value);
724 return this;
725 }
726
727 /**
728 * This method will cause the View's <code>alpha</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800729 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800730 *
731 * @param value The value to be animated to.
732 * @see View#setAlpha(float)
733 * @return This object, allowing calls to methods in this class to be chained.
734 */
735 public ViewPropertyAnimator alpha(float value) {
736 animateProperty(ALPHA, value);
737 return this;
738 }
739
740 /**
741 * This method will cause the View's <code>alpha</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800742 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800743 *
744 * @param value The amount to be animated by, as an offset from the current value.
745 * @see View#setAlpha(float)
746 * @return This object, allowing calls to methods in this class to be chained.
747 */
748 public ViewPropertyAnimator alphaBy(float value) {
749 animatePropertyBy(ALPHA, value);
750 return this;
751 }
752
753 /**
Chet Haasec1ca6652012-01-31 07:33:48 -0800754 * The View associated with this ViewPropertyAnimator will have its
755 * {@link View#setLayerType(int, android.graphics.Paint) layer type} set to
Chet Haasecb150fe2012-05-03 15:15:05 -0700756 * {@link View#LAYER_TYPE_HARDWARE} for the duration of the next animation.
757 * As stated in the documentation for {@link View#LAYER_TYPE_HARDWARE},
758 * the actual type of layer used internally depends on the runtime situation of the
759 * view. If the activity and this view are hardware-accelerated, then the layer will be
760 * accelerated as well. If the activity or the view is not accelerated, then the layer will
761 * effectively be the same as {@link View#LAYER_TYPE_SOFTWARE}.
762 *
763 * <p>This state is not persistent, either on the View or on this ViewPropertyAnimator: the
764 * layer type of the View will be restored when the animation ends to what it was when this
765 * method was called, and this setting on ViewPropertyAnimator is only valid for the next
766 * animation. Note that calling this method and then independently setting the layer type of
767 * the View (by a direct call to {@link View#setLayerType(int, android.graphics.Paint)}) will
768 * result in some inconsistency, including having the layer type restored to its pre-withLayer()
769 * value when the animation ends.</p>
Chet Haasec1ca6652012-01-31 07:33:48 -0800770 *
771 * @see View#setLayerType(int, android.graphics.Paint)
772 * @return This object, allowing calls to methods in this class to be chained.
773 */
774 public ViewPropertyAnimator withLayer() {
775 mPendingSetupAction= new Runnable() {
776 @Override
777 public void run() {
778 mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
Chet Haase5fd37232013-09-13 19:01:52 -0700779 if (mView.isAttachedToWindow()) {
780 mView.buildLayer();
781 }
Chet Haasec1ca6652012-01-31 07:33:48 -0800782 }
783 };
784 final int currentLayerType = mView.getLayerType();
785 mPendingCleanupAction = new Runnable() {
786 @Override
787 public void run() {
788 mView.setLayerType(currentLayerType, null);
789 }
790 };
791 if (mAnimatorSetupMap == null) {
792 mAnimatorSetupMap = new HashMap<Animator, Runnable>();
793 }
794 if (mAnimatorCleanupMap == null) {
795 mAnimatorCleanupMap = new HashMap<Animator, Runnable>();
796 }
797
798 return this;
799 }
800
801 /**
802 * Specifies an action to take place when the next animation runs. If there is a
803 * {@link #setStartDelay(long) startDelay} set on this ViewPropertyAnimator, then the
804 * action will run after that startDelay expires, when the actual animation begins.
805 * This method, along with {@link #withEndAction(Runnable)}, is intended to help facilitate
806 * choreographing ViewPropertyAnimator animations with other animations or actions
807 * in the application.
808 *
809 * @param runnable The action to run when the next animation starts.
810 * @return This object, allowing calls to methods in this class to be chained.
811 */
812 public ViewPropertyAnimator withStartAction(Runnable runnable) {
813 mPendingOnStartAction = runnable;
814 if (runnable != null && mAnimatorOnStartMap == null) {
815 mAnimatorOnStartMap = new HashMap<Animator, Runnable>();
816 }
817 return this;
818 }
819
820 /**
821 * Specifies an action to take place when the next animation ends. The action is only
822 * run if the animation ends normally; if the ViewPropertyAnimator is canceled during
823 * that animation, the runnable will not run.
824 * This method, along with {@link #withStartAction(Runnable)}, is intended to help facilitate
825 * choreographing ViewPropertyAnimator animations with other animations or actions
826 * in the application.
827 *
828 * <p>For example, the following code animates a view to x=200 and then back to 0:</p>
829 * <pre>
830 * Runnable endAction = new Runnable() {
831 * public void run() {
832 * view.animate().x(0);
833 * }
834 * };
Robert Ly8ee2a702012-12-17 15:00:08 -0800835 * view.animate().x(200).withEndAction(endAction);
Chet Haasec1ca6652012-01-31 07:33:48 -0800836 * </pre>
837 *
838 * @param runnable The action to run when the next animation ends.
839 * @return This object, allowing calls to methods in this class to be chained.
840 */
841 public ViewPropertyAnimator withEndAction(Runnable runnable) {
842 mPendingOnEndAction = runnable;
843 if (runnable != null && mAnimatorOnEndMap == null) {
844 mAnimatorOnEndMap = new HashMap<Animator, Runnable>();
845 }
846 return this;
847 }
848
John Reck918988c2014-05-19 10:28:35 -0700849 boolean hasActions() {
850 return mPendingSetupAction != null
851 || mPendingCleanupAction != null
852 || mPendingOnStartAction != null
853 || mPendingOnEndAction != null;
854 }
855
Chet Haasec1ca6652012-01-31 07:33:48 -0800856 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800857 * Starts the underlying Animator for a set of properties. We use a single animator that
858 * simply runs from 0 to 1, and then use that fractional value to set each property
859 * value accordingly.
860 */
861 private void startAnimation() {
John Reck918988c2014-05-19 10:28:35 -0700862 if (mRTBackend != null && mRTBackend.startAnimation(this)) {
863 return;
864 }
Chet Haase563d4f22012-04-18 16:20:08 -0700865 mView.setHasTransientState(true);
Chet Haasea00f3862011-02-22 06:34:40 -0800866 ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
867 ArrayList<NameValuesHolder> nameValueList =
868 (ArrayList<NameValuesHolder>) mPendingAnimations.clone();
869 mPendingAnimations.clear();
870 int propertyMask = 0;
871 int propertyCount = nameValueList.size();
872 for (int i = 0; i < propertyCount; ++i) {
873 NameValuesHolder nameValuesHolder = nameValueList.get(i);
874 propertyMask |= nameValuesHolder.mNameConstant;
875 }
Chet Haasea00f3862011-02-22 06:34:40 -0800876 mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
Chet Haasec1ca6652012-01-31 07:33:48 -0800877 if (mPendingSetupAction != null) {
878 mAnimatorSetupMap.put(animator, mPendingSetupAction);
879 mPendingSetupAction = null;
880 }
881 if (mPendingCleanupAction != null) {
882 mAnimatorCleanupMap.put(animator, mPendingCleanupAction);
883 mPendingCleanupAction = null;
884 }
885 if (mPendingOnStartAction != null) {
886 mAnimatorOnStartMap.put(animator, mPendingOnStartAction);
887 mPendingOnStartAction = null;
888 }
889 if (mPendingOnEndAction != null) {
890 mAnimatorOnEndMap.put(animator, mPendingOnEndAction);
891 mPendingOnEndAction = null;
892 }
Chet Haasea00f3862011-02-22 06:34:40 -0800893 animator.addUpdateListener(mAnimatorEventListener);
894 animator.addListener(mAnimatorEventListener);
Chet Haasecbbd93a2011-08-08 17:34:25 -0700895 if (mStartDelaySet) {
896 animator.setStartDelay(mStartDelay);
897 }
Chet Haasea00f3862011-02-22 06:34:40 -0800898 if (mDurationSet) {
899 animator.setDuration(mDuration);
900 }
Vladislav Kaznacheev78f146f2015-06-15 06:58:59 +0000901 if (mInterpolatorSet) {
Chet Haasea00f3862011-02-22 06:34:40 -0800902 animator.setInterpolator(mInterpolator);
903 }
904 animator.start();
905 }
906
907 /**
908 * Utility function, called by the various x(), y(), etc. methods. This stores the
Chet Haased666cf32011-03-01 07:31:30 -0800909 * constant name for the property along with the from/delta values that will be used to
Chet Haasea00f3862011-02-22 06:34:40 -0800910 * calculate and set the property during the animation. This structure is added to the
911 * pending animations, awaiting the eventual start() of the underlying animator. A
912 * Runnable is posted to start the animation, and any pending such Runnable is canceled
913 * (which enables us to end up starting just one animator for all of the properties
914 * specified at one time).
915 *
916 * @param constantName The specifier for the property being animated
917 * @param toValue The value to which the property will animate
918 */
919 private void animateProperty(int constantName, float toValue) {
920 float fromValue = getValue(constantName);
921 float deltaValue = toValue - fromValue;
922 animatePropertyBy(constantName, fromValue, deltaValue);
923 }
924
925 /**
926 * Utility function, called by the various xBy(), yBy(), etc. methods. This method is
927 * just like animateProperty(), except the value is an offset from the property's
928 * current value, instead of an absolute "to" value.
929 *
930 * @param constantName The specifier for the property being animated
931 * @param byValue The amount by which the property will change
932 */
933 private void animatePropertyBy(int constantName, float byValue) {
934 float fromValue = getValue(constantName);
935 animatePropertyBy(constantName, fromValue, byValue);
936 }
937
938 /**
Chet Haased666cf32011-03-01 07:31:30 -0800939 * Utility function, called by animateProperty() and animatePropertyBy(), which handles the
Chet Haasea00f3862011-02-22 06:34:40 -0800940 * details of adding a pending animation and posting the request to start the animation.
941 *
942 * @param constantName The specifier for the property being animated
Chet Haased666cf32011-03-01 07:31:30 -0800943 * @param startValue The starting value of the property
Chet Haasea00f3862011-02-22 06:34:40 -0800944 * @param byValue The amount by which the property will change
945 */
Chet Haased666cf32011-03-01 07:31:30 -0800946 private void animatePropertyBy(int constantName, float startValue, float byValue) {
Chet Haaseba592d202011-02-25 11:35:17 -0800947 // First, cancel any existing animations on this property
948 if (mAnimatorMap.size() > 0) {
949 Animator animatorToCancel = null;
950 Set<Animator> animatorSet = mAnimatorMap.keySet();
951 for (Animator runningAnim : animatorSet) {
952 PropertyBundle bundle = mAnimatorMap.get(runningAnim);
953 if (bundle.cancel(constantName)) {
954 // property was canceled - cancel the animation if it's now empty
955 // Note that it's safe to break out here because every new animation
956 // on a property will cancel a previous animation on that property, so
957 // there can only ever be one such animation running.
958 if (bundle.mPropertyMask == NONE) {
Chet Haase8d5f8082011-05-24 08:03:16 -0700959 // the animation is no longer changing anything - cancel it
Chet Haaseba592d202011-02-25 11:35:17 -0800960 animatorToCancel = runningAnim;
961 break;
962 }
963 }
964 }
965 if (animatorToCancel != null) {
966 animatorToCancel.cancel();
967 }
968 }
969
Chet Haasea00f3862011-02-22 06:34:40 -0800970 NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
971 mPendingAnimations.add(nameValuePair);
Chet Haase3a000a52011-06-16 13:55:11 -0700972 mView.removeCallbacks(mAnimationStarter);
Chet Haasedcfbd6a2013-05-09 14:40:21 -0700973 mView.postOnAnimation(mAnimationStarter);
Chet Haasea00f3862011-02-22 06:34:40 -0800974 }
975
976 /**
977 * This method handles setting the property values directly in the View object's fields.
978 * propertyConstant tells it which property should be set, value is the value to set
979 * the property to.
980 *
981 * @param propertyConstant The property to be set
982 * @param value The value to set the property to
983 */
984 private void setValue(int propertyConstant, float value) {
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700985 final View.TransformationInfo info = mView.mTransformationInfo;
Chris Craik64a12e12014-03-28 18:12:12 -0700986 final RenderNode renderNode = mView.mRenderNode;
Chet Haasea00f3862011-02-22 06:34:40 -0800987 switch (propertyConstant) {
988 case TRANSLATION_X:
Chris Craik49e6c732014-03-31 12:34:11 -0700989 renderNode.setTranslationX(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800990 break;
991 case TRANSLATION_Y:
Chris Craik49e6c732014-03-31 12:34:11 -0700992 renderNode.setTranslationY(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800993 break;
Chris Craikf57776b2013-10-25 18:30:17 -0700994 case TRANSLATION_Z:
Chris Craik49e6c732014-03-31 12:34:11 -0700995 renderNode.setTranslationZ(value);
Chris Craikf57776b2013-10-25 18:30:17 -0700996 break;
Chet Haasea00f3862011-02-22 06:34:40 -0800997 case ROTATION:
Chris Craik49e6c732014-03-31 12:34:11 -0700998 renderNode.setRotation(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800999 break;
1000 case ROTATION_X:
Chris Craik49e6c732014-03-31 12:34:11 -07001001 renderNode.setRotationX(value);
Chet Haasea00f3862011-02-22 06:34:40 -08001002 break;
1003 case ROTATION_Y:
Chris Craik49e6c732014-03-31 12:34:11 -07001004 renderNode.setRotationY(value);
Chet Haasea00f3862011-02-22 06:34:40 -08001005 break;
1006 case SCALE_X:
Chris Craik49e6c732014-03-31 12:34:11 -07001007 renderNode.setScaleX(value);
Chet Haasea00f3862011-02-22 06:34:40 -08001008 break;
1009 case SCALE_Y:
Chris Craik49e6c732014-03-31 12:34:11 -07001010 renderNode.setScaleY(value);
Chet Haasea00f3862011-02-22 06:34:40 -08001011 break;
1012 case X:
Chris Craik49e6c732014-03-31 12:34:11 -07001013 renderNode.setTranslationX(value - mView.mLeft);
Chet Haasea00f3862011-02-22 06:34:40 -08001014 break;
1015 case Y:
Chris Craik49e6c732014-03-31 12:34:11 -07001016 renderNode.setTranslationY(value - mView.mTop);
Chet Haasea00f3862011-02-22 06:34:40 -08001017 break;
Chris Craikcc39e162014-04-25 18:34:11 -07001018 case Z:
1019 renderNode.setTranslationZ(value - renderNode.getElevation());
1020 break;
Chet Haasea00f3862011-02-22 06:34:40 -08001021 case ALPHA:
Dianne Hackbornddb715b2011-09-09 14:43:39 -07001022 info.mAlpha = value;
Chris Craik49e6c732014-03-31 12:34:11 -07001023 renderNode.setAlpha(value);
Chet Haasea00f3862011-02-22 06:34:40 -08001024 break;
1025 }
1026 }
1027
1028 /**
1029 * This method gets the value of the named property from the View object.
1030 *
1031 * @param propertyConstant The property whose value should be returned
1032 * @return float The value of the named property
1033 */
1034 private float getValue(int propertyConstant) {
Chris Craik49e6c732014-03-31 12:34:11 -07001035 final RenderNode node = mView.mRenderNode;
Chet Haasea00f3862011-02-22 06:34:40 -08001036 switch (propertyConstant) {
1037 case TRANSLATION_X:
Chris Craik49e6c732014-03-31 12:34:11 -07001038 return node.getTranslationX();
Chet Haasea00f3862011-02-22 06:34:40 -08001039 case TRANSLATION_Y:
Chris Craik49e6c732014-03-31 12:34:11 -07001040 return node.getTranslationY();
Chris Craikf57776b2013-10-25 18:30:17 -07001041 case TRANSLATION_Z:
Chris Craik49e6c732014-03-31 12:34:11 -07001042 return node.getTranslationZ();
Chet Haasea00f3862011-02-22 06:34:40 -08001043 case ROTATION:
Chris Craik49e6c732014-03-31 12:34:11 -07001044 return node.getRotation();
Chet Haasea00f3862011-02-22 06:34:40 -08001045 case ROTATION_X:
Chris Craik49e6c732014-03-31 12:34:11 -07001046 return node.getRotationX();
Chet Haasea00f3862011-02-22 06:34:40 -08001047 case ROTATION_Y:
Chris Craik49e6c732014-03-31 12:34:11 -07001048 return node.getRotationY();
Chet Haasea00f3862011-02-22 06:34:40 -08001049 case SCALE_X:
Chris Craik49e6c732014-03-31 12:34:11 -07001050 return node.getScaleX();
Chet Haasea00f3862011-02-22 06:34:40 -08001051 case SCALE_Y:
Chris Craik49e6c732014-03-31 12:34:11 -07001052 return node.getScaleY();
Chet Haasea00f3862011-02-22 06:34:40 -08001053 case X:
Chris Craik49e6c732014-03-31 12:34:11 -07001054 return mView.mLeft + node.getTranslationX();
Chet Haasea00f3862011-02-22 06:34:40 -08001055 case Y:
Chris Craik49e6c732014-03-31 12:34:11 -07001056 return mView.mTop + node.getTranslationY();
Chris Craikcc39e162014-04-25 18:34:11 -07001057 case Z:
1058 return node.getElevation() + node.getTranslationZ();
Chet Haasea00f3862011-02-22 06:34:40 -08001059 case ALPHA:
Chris Craik49e6c732014-03-31 12:34:11 -07001060 return mView.mTransformationInfo.mAlpha;
Chet Haasea00f3862011-02-22 06:34:40 -08001061 }
1062 return 0;
1063 }
1064
1065 /**
1066 * Utility class that handles the various Animator events. The only ones we care
1067 * about are the end event (which we use to clean up the animator map when an animator
1068 * finishes) and the update event (which we use to calculate the current value of each
1069 * property and then set it on the view object).
1070 */
1071 private class AnimatorEventListener
1072 implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
1073 @Override
1074 public void onAnimationStart(Animator animation) {
Chet Haasec1ca6652012-01-31 07:33:48 -08001075 if (mAnimatorSetupMap != null) {
1076 Runnable r = mAnimatorSetupMap.get(animation);
1077 if (r != null) {
1078 r.run();
1079 }
1080 mAnimatorSetupMap.remove(animation);
1081 }
1082 if (mAnimatorOnStartMap != null) {
1083 Runnable r = mAnimatorOnStartMap.get(animation);
1084 if (r != null) {
1085 r.run();
1086 }
1087 mAnimatorOnStartMap.remove(animation);
1088 }
Chet Haasea00f3862011-02-22 06:34:40 -08001089 if (mListener != null) {
1090 mListener.onAnimationStart(animation);
1091 }
1092 }
1093
1094 @Override
1095 public void onAnimationCancel(Animator animation) {
1096 if (mListener != null) {
1097 mListener.onAnimationCancel(animation);
1098 }
Chet Haasec1ca6652012-01-31 07:33:48 -08001099 if (mAnimatorOnEndMap != null) {
1100 mAnimatorOnEndMap.remove(animation);
1101 }
Chet Haasea00f3862011-02-22 06:34:40 -08001102 }
1103
1104 @Override
1105 public void onAnimationRepeat(Animator animation) {
1106 if (mListener != null) {
1107 mListener.onAnimationRepeat(animation);
1108 }
1109 }
1110
1111 @Override
1112 public void onAnimationEnd(Animator animation) {
Chet Haase563d4f22012-04-18 16:20:08 -07001113 mView.setHasTransientState(false);
George Mountf643fb02016-03-31 15:45:35 +00001114 if (mAnimatorCleanupMap != null) {
1115 Runnable r = mAnimatorCleanupMap.get(animation);
1116 if (r != null) {
1117 r.run();
1118 }
1119 mAnimatorCleanupMap.remove(animation);
1120 }
Chet Haasea00f3862011-02-22 06:34:40 -08001121 if (mListener != null) {
1122 mListener.onAnimationEnd(animation);
1123 }
George Mounte9a4f872016-03-29 07:39:02 -07001124 if (mAnimatorOnEndMap != null) {
1125 Runnable r = mAnimatorOnEndMap.get(animation);
1126 if (r != null) {
1127 r.run();
1128 }
1129 mAnimatorOnEndMap.remove(animation);
1130 }
Chet Haasea00f3862011-02-22 06:34:40 -08001131 mAnimatorMap.remove(animation);
1132 }
1133
1134 /**
1135 * Calculate the current value for each property and set it on the view. Invalidate
1136 * the view object appropriately, depending on which properties are being animated.
1137 *
1138 * @param animation The animator associated with the properties that need to be
1139 * set. This animator holds the animation fraction which we will use to calculate
1140 * the current value of each property.
1141 */
1142 @Override
1143 public void onAnimationUpdate(ValueAnimator animation) {
Chet Haase0c6d83cc2011-12-01 08:38:13 -08001144 PropertyBundle propertyBundle = mAnimatorMap.get(animation);
1145 if (propertyBundle == null) {
1146 // Shouldn't happen, but just to play it safe
1147 return;
1148 }
Chris Craik30485452014-05-27 19:18:10 -07001149
1150 boolean hardwareAccelerated = mView.isHardwareAccelerated();
Chet Haase9d1992d2012-03-13 11:03:25 -07001151
Chet Haasea00f3862011-02-22 06:34:40 -08001152 // alpha requires slightly different treatment than the other (transform) properties.
1153 // The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
1154 // logic is dependent on how the view handles an internal call to onSetAlpha().
1155 // We track what kinds of properties are set, and how alpha is handled when it is
1156 // set, and perform the invalidation steps appropriately.
1157 boolean alphaHandled = false;
Chris Craik30485452014-05-27 19:18:10 -07001158 if (!hardwareAccelerated) {
Chet Haase9d1992d2012-03-13 11:03:25 -07001159 mView.invalidateParentCaches();
1160 }
Chet Haasea00f3862011-02-22 06:34:40 -08001161 float fraction = animation.getAnimatedFraction();
Chet Haasea00f3862011-02-22 06:34:40 -08001162 int propertyMask = propertyBundle.mPropertyMask;
1163 if ((propertyMask & TRANSFORM_MASK) != 0) {
Chris Craik30485452014-05-27 19:18:10 -07001164 mView.invalidateViewProperty(hardwareAccelerated, false);
Chet Haasea00f3862011-02-22 06:34:40 -08001165 }
1166 ArrayList<NameValuesHolder> valueList = propertyBundle.mNameValuesHolder;
1167 if (valueList != null) {
1168 int count = valueList.size();
1169 for (int i = 0; i < count; ++i) {
1170 NameValuesHolder values = valueList.get(i);
1171 float value = values.mFromValue + fraction * values.mDeltaValue;
1172 if (values.mNameConstant == ALPHA) {
1173 alphaHandled = mView.setAlphaNoInvalidation(value);
1174 } else {
1175 setValue(values.mNameConstant, value);
1176 }
1177 }
1178 }
1179 if ((propertyMask & TRANSFORM_MASK) != 0) {
Chris Craik30485452014-05-27 19:18:10 -07001180 if (!hardwareAccelerated) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001181 mView.mPrivateFlags |= View.PFLAG_DRAWN; // force another invalidation
Chet Haase9d1992d2012-03-13 11:03:25 -07001182 }
Chet Haasea00f3862011-02-22 06:34:40 -08001183 }
1184 // invalidate(false) in all cases except if alphaHandled gets set to true
1185 // via the call to setAlphaNoInvalidation(), above
Chet Haase9d1992d2012-03-13 11:03:25 -07001186 if (alphaHandled) {
1187 mView.invalidate(true);
1188 } else {
1189 mView.invalidateViewProperty(false, false);
1190 }
Chet Haase87f4ae62013-09-06 18:29:56 -07001191 if (mUpdateListener != null) {
1192 mUpdateListener.onAnimationUpdate(animation);
1193 }
Chet Haasea00f3862011-02-22 06:34:40 -08001194 }
1195 }
1196}