blob: 67a94be5959107434d3de9b506afe01d836165d3 [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;
20import android.animation.ValueAnimator;
21import android.animation.TimeInterpolator;
22
23import 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>
46 *
47 */
48public class ViewPropertyAnimator {
49
50 /**
51 * The View whose properties are being animated by this class. This is set at
52 * construction time.
53 */
Dianne Hackbornddb715b2011-09-09 14:43:39 -070054 private 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
84 * 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.
86 */
87 private TimeInterpolator mInterpolator;
88
89 /**
90 * 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 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800112 * This listener is the mechanism by which the underlying Animator causes changes to the
113 * properties currently being animated, as well as the cleanup after an animation is
114 * complete.
115 */
116 private AnimatorEventListener mAnimatorEventListener = new AnimatorEventListener();
117
118 /**
119 * This list holds the properties that have been asked to animate. We allow the caller to
120 * request several animations prior to actually starting the underlying animator. This
121 * enables us to run one single animator to handle several properties in parallel. Each
122 * property is tossed onto the pending list until the animation actually starts (which is
123 * done by posting it onto mView), at which time the pending list is cleared and the properties
124 * on that list are added to the list of properties associated with that animator.
125 */
126 ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();
Chet Haasec1ca6652012-01-31 07:33:48 -0800127 private Runnable mPendingSetupAction;
128 private Runnable mPendingCleanupAction;
129 private Runnable mPendingOnStartAction;
130 private Runnable mPendingOnEndAction;
Chet Haasea00f3862011-02-22 06:34:40 -0800131
132 /**
133 * Constants used to associate a property being requested and the mechanism used to set
Chet Haased666cf32011-03-01 07:31:30 -0800134 * the property (this class calls directly into View to set the properties in question).
Chet Haasea00f3862011-02-22 06:34:40 -0800135 */
136 private static final int NONE = 0x0000;
137 private static final int TRANSLATION_X = 0x0001;
138 private static final int TRANSLATION_Y = 0x0002;
139 private static final int SCALE_X = 0x0004;
140 private static final int SCALE_Y = 0x0008;
141 private static final int ROTATION = 0x0010;
142 private static final int ROTATION_X = 0x0020;
143 private static final int ROTATION_Y = 0x0040;
144 private static final int X = 0x0080;
145 private static final int Y = 0x0100;
146 private static final int ALPHA = 0x0200;
147
148 private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | SCALE_X | SCALE_Y |
149 ROTATION | ROTATION_X | ROTATION_Y | X | Y;
150
151 /**
152 * The mechanism by which the user can request several properties that are then animated
153 * together works by posting this Runnable to start the underlying Animator. Every time
154 * a property animation is requested, we cancel any previous postings of the Runnable
155 * and re-post it. This means that we will only ever run the Runnable (and thus start the
156 * underlying animator) after the caller is done setting the properties that should be
157 * animated together.
158 */
159 private Runnable mAnimationStarter = new Runnable() {
160 @Override
161 public void run() {
162 startAnimation();
163 }
164 };
165
166 /**
167 * This class holds information about the overall animation being run on the set of
168 * properties. The mask describes which properties are being animated and the
169 * values holder is the list of all property/value objects.
170 */
171 private static class PropertyBundle {
172 int mPropertyMask;
173 ArrayList<NameValuesHolder> mNameValuesHolder;
Chet Haaseba592d202011-02-25 11:35:17 -0800174
Chet Haasea00f3862011-02-22 06:34:40 -0800175 PropertyBundle(int propertyMask, ArrayList<NameValuesHolder> nameValuesHolder) {
176 mPropertyMask = propertyMask;
177 mNameValuesHolder = nameValuesHolder;
178 }
Chet Haaseba592d202011-02-25 11:35:17 -0800179
180 /**
181 * Removes the given property from being animated as a part of this
182 * PropertyBundle. If the property was a part of this bundle, it returns
183 * true to indicate that it was, in fact, canceled. This is an indication
184 * to the caller that a cancellation actually occurred.
185 *
186 * @param propertyConstant The property whose cancellation is requested.
187 * @return true if the given property is a part of this bundle and if it
188 * has therefore been canceled.
189 */
190 boolean cancel(int propertyConstant) {
191 if ((mPropertyMask & propertyConstant) != 0 && mNameValuesHolder != null) {
192 int count = mNameValuesHolder.size();
193 for (int i = 0; i < count; ++i) {
194 NameValuesHolder nameValuesHolder = mNameValuesHolder.get(i);
195 if (nameValuesHolder.mNameConstant == propertyConstant) {
196 mNameValuesHolder.remove(i);
197 mPropertyMask &= ~propertyConstant;
198 return true;
199 }
200 }
201 }
202 return false;
203 }
Chet Haasea00f3862011-02-22 06:34:40 -0800204 }
205
206 /**
207 * This list tracks the list of properties being animated by any particular animator.
208 * In most situations, there would only ever be one animator running at a time. But it is
209 * possible to request some properties to animate together, then while those properties
210 * are animating, to request some other properties to animate together. The way that
211 * works is by having this map associate the group of properties being animated with the
212 * animator handling the animation. On every update event for an Animator, we ask the
213 * map for the associated properties and set them accordingly.
214 */
215 private HashMap<Animator, PropertyBundle> mAnimatorMap =
216 new HashMap<Animator, PropertyBundle>();
Chet Haasec1ca6652012-01-31 07:33:48 -0800217 private HashMap<Animator, Runnable> mAnimatorSetupMap;
218 private HashMap<Animator, Runnable> mAnimatorCleanupMap;
219 private HashMap<Animator, Runnable> mAnimatorOnStartMap;
220 private HashMap<Animator, Runnable> mAnimatorOnEndMap;
Chet Haasea00f3862011-02-22 06:34:40 -0800221
222 /**
223 * This is the information we need to set each property during the animation.
224 * mNameConstant is used to set the appropriate field in View, and the from/delta
225 * values are used to calculate the animated value for a given animation fraction
226 * during the animation.
227 */
228 private static class NameValuesHolder {
229 int mNameConstant;
230 float mFromValue;
231 float mDeltaValue;
232 NameValuesHolder(int nameConstant, float fromValue, float deltaValue) {
233 mNameConstant = nameConstant;
234 mFromValue = fromValue;
235 mDeltaValue = deltaValue;
236 }
237 }
238
239 /**
240 * Constructor, called by View. This is private by design, as the user should only
241 * get a ViewPropertyAnimator by calling View.animate().
242 *
243 * @param view The View associated with this ViewPropertyAnimator
244 */
245 ViewPropertyAnimator(View view) {
246 mView = view;
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700247 view.ensureTransformationInfo();
Chet Haasea00f3862011-02-22 06:34:40 -0800248 }
249
250 /**
251 * Sets the duration for the underlying animator that animates the requested properties.
252 * By default, the animator uses the default value for ValueAnimator. Calling this method
253 * will cause the declared value to be used instead.
254 * @param duration The length of ensuing property animations, in milliseconds. The value
255 * cannot be negative.
256 * @return This object, allowing calls to methods in this class to be chained.
257 */
258 public ViewPropertyAnimator setDuration(long duration) {
259 if (duration < 0) {
260 throw new IllegalArgumentException("Animators cannot have negative duration: " +
261 duration);
262 }
263 mDurationSet = true;
264 mDuration = duration;
265 return this;
266 }
267
268 /**
Chet Haase8d5f8082011-05-24 08:03:16 -0700269 * Returns the current duration of property animations. If the duration was set on this
270 * object, that value is returned. Otherwise, the default value of the underlying Animator
271 * is returned.
272 *
273 * @see #setDuration(long)
274 * @return The duration of animations, in milliseconds.
275 */
276 public long getDuration() {
Chet Haasecbbd93a2011-08-08 17:34:25 -0700277 if (mDurationSet) {
278 return mDuration;
Chet Haase8d5f8082011-05-24 08:03:16 -0700279 } else {
280 // Just return the default from ValueAnimator, since that's what we'd get if
281 // the value has not been set otherwise
Cyril Mottierd40acfb2013-07-25 10:08:29 +0200282 if (mTempValueAnimator == null) {
283 mTempValueAnimator = new ValueAnimator();
284 }
285 return mTempValueAnimator.getDuration();
Chet Haase8d5f8082011-05-24 08:03:16 -0700286 }
287 }
288
289 /**
290 * Returns the current startDelay of property animations. If the startDelay was set on this
291 * object, that value is returned. Otherwise, the default value of the underlying Animator
292 * is returned.
293 *
294 * @see #setStartDelay(long)
295 * @return The startDelay of animations, in milliseconds.
296 */
297 public long getStartDelay() {
298 if (mStartDelaySet) {
299 return mStartDelay;
300 } else {
301 // Just return the default from ValueAnimator (0), since that's what we'd get if
302 // the value has not been set otherwise
303 return 0;
304 }
305 }
306
307 /**
308 * Sets the startDelay for the underlying animator that animates the requested properties.
309 * By default, the animator uses the default value for ValueAnimator. Calling this method
310 * will cause the declared value to be used instead.
311 * @param startDelay The delay of ensuing property animations, in milliseconds. The value
312 * cannot be negative.
313 * @return This object, allowing calls to methods in this class to be chained.
314 */
315 public ViewPropertyAnimator setStartDelay(long startDelay) {
316 if (startDelay < 0) {
317 throw new IllegalArgumentException("Animators cannot have negative duration: " +
318 startDelay);
319 }
320 mStartDelaySet = true;
321 mStartDelay = startDelay;
322 return this;
323 }
324
325 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800326 * Sets the interpolator for the underlying animator that animates the requested properties.
327 * By default, the animator uses the default interpolator for ValueAnimator. Calling this method
328 * will cause the declared object to be used instead.
329 *
330 * @param interpolator The TimeInterpolator to be used for ensuing property animations.
331 * @return This object, allowing calls to methods in this class to be chained.
332 */
333 public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) {
334 mInterpolatorSet = true;
335 mInterpolator = interpolator;
336 return this;
337 }
338
339 /**
Chet Haase430742f2013-04-12 11:18:36 -0700340 * Returns the timing interpolator that this animation uses.
341 *
342 * @return The timing interpolator for this animation.
343 */
344 public TimeInterpolator getInterpolator() {
Cyril Mottierd40acfb2013-07-25 10:08:29 +0200345 if (mInterpolatorSet) {
346 return mInterpolator;
347 } else {
348 // Just return the default from ValueAnimator, since that's what we'd get if
349 // the value has not been set otherwise
350 if (mTempValueAnimator == null) {
351 mTempValueAnimator = new ValueAnimator();
352 }
353 return mTempValueAnimator.getInterpolator();
354 }
Chet Haase430742f2013-04-12 11:18:36 -0700355 }
356
357 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800358 * Sets a listener for events in the underlying Animators that run the property
359 * animations.
360 *
Chet Haase87f4ae62013-09-06 18:29:56 -0700361 * @see Animator.AnimatorListener
362 *
363 * @param listener The listener to be called with AnimatorListener events. A value of
364 * <code>null</code> removes any existing listener.
Chet Haasea00f3862011-02-22 06:34:40 -0800365 * @return This object, allowing calls to methods in this class to be chained.
366 */
367 public ViewPropertyAnimator setListener(Animator.AnimatorListener listener) {
368 mListener = listener;
369 return this;
370 }
371
372 /**
Chet Haase87f4ae62013-09-06 18:29:56 -0700373 * Sets a listener for update events in the underlying ValueAnimator that runs
374 * the property animations. Note that the underlying animator is animating between
375 * 0 and 1 (these values are then turned into the actual property values internally
376 * by ViewPropertyAnimator). So the animator cannot give information on the current
377 * values of the properties being animated by this ViewPropertyAnimator, although
378 * the view object itself can be queried to get the current values.
379 *
380 * @see android.animation.ValueAnimator.AnimatorUpdateListener
381 *
382 * @param listener The listener to be called with update events. A value of
383 * <code>null</code> removes any existing listener.
384 * @return This object, allowing calls to methods in this class to be chained.
385 */
386 public ViewPropertyAnimator setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) {
387 mUpdateListener = listener;
388 return this;
389 }
390
391 /**
Chet Haase8d5f8082011-05-24 08:03:16 -0700392 * Starts the currently pending property animations immediately. Calling <code>start()</code>
393 * is optional because all animations start automatically at the next opportunity. However,
394 * if the animations are needed to start immediately and synchronously (not at the time when
395 * the next event is processed by the hierarchy, which is when the animations would begin
396 * otherwise), then this method can be used.
397 */
398 public void start() {
Michael Jurka500998d2012-05-13 15:35:02 -0700399 mView.removeCallbacks(mAnimationStarter);
Chet Haase8d5f8082011-05-24 08:03:16 -0700400 startAnimation();
401 }
402
403 /**
404 * Cancels all property animations that are currently running or pending.
405 */
406 public void cancel() {
407 if (mAnimatorMap.size() > 0) {
408 HashMap<Animator, PropertyBundle> mAnimatorMapCopy =
409 (HashMap<Animator, PropertyBundle>)mAnimatorMap.clone();
410 Set<Animator> animatorSet = mAnimatorMapCopy.keySet();
411 for (Animator runningAnim : animatorSet) {
412 runningAnim.cancel();
413 }
414 }
415 mPendingAnimations.clear();
Chet Haase3a000a52011-06-16 13:55:11 -0700416 mView.removeCallbacks(mAnimationStarter);
Chet Haase8d5f8082011-05-24 08:03:16 -0700417 }
418
419 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800420 * This method will cause the View's <code>x</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800421 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800422 *
423 * @param value The value to be animated to.
424 * @see View#setX(float)
425 * @return This object, allowing calls to methods in this class to be chained.
426 */
427 public ViewPropertyAnimator x(float value) {
428 animateProperty(X, value);
429 return this;
430 }
431
432 /**
433 * This method will cause the View's <code>x</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800434 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800435 *
436 * @param value The amount to be animated by, as an offset from the current value.
437 * @see View#setX(float)
438 * @return This object, allowing calls to methods in this class to be chained.
439 */
440 public ViewPropertyAnimator xBy(float value) {
441 animatePropertyBy(X, value);
442 return this;
443 }
444
445 /**
446 * This method will cause the View's <code>y</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800447 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800448 *
449 * @param value The value to be animated to.
450 * @see View#setY(float)
451 * @return This object, allowing calls to methods in this class to be chained.
452 */
453 public ViewPropertyAnimator y(float value) {
454 animateProperty(Y, value);
455 return this;
456 }
457
458 /**
459 * This method will cause the View's <code>y</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800460 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800461 *
462 * @param value The amount to be animated by, as an offset from the current value.
463 * @see View#setY(float)
464 * @return This object, allowing calls to methods in this class to be chained.
465 */
466 public ViewPropertyAnimator yBy(float value) {
467 animatePropertyBy(Y, value);
468 return this;
469 }
470
471 /**
472 * This method will cause the View's <code>rotation</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800473 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800474 *
475 * @param value The value to be animated to.
476 * @see View#setRotation(float)
477 * @return This object, allowing calls to methods in this class to be chained.
478 */
479 public ViewPropertyAnimator rotation(float value) {
480 animateProperty(ROTATION, value);
481 return this;
482 }
483
484 /**
485 * This method will cause the View's <code>rotation</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800486 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800487 *
488 * @param value The amount to be animated by, as an offset from the current value.
489 * @see View#setRotation(float)
490 * @return This object, allowing calls to methods in this class to be chained.
491 */
492 public ViewPropertyAnimator rotationBy(float value) {
493 animatePropertyBy(ROTATION, value);
494 return this;
495 }
496
497 /**
498 * This method will cause the View's <code>rotationX</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800499 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800500 *
501 * @param value The value to be animated to.
502 * @see View#setRotationX(float)
503 * @return This object, allowing calls to methods in this class to be chained.
504 */
505 public ViewPropertyAnimator rotationX(float value) {
506 animateProperty(ROTATION_X, value);
507 return this;
508 }
509
510 /**
511 * This method will cause the View's <code>rotationX</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800512 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800513 *
514 * @param value The amount to be animated by, as an offset from the current value.
515 * @see View#setRotationX(float)
516 * @return This object, allowing calls to methods in this class to be chained.
517 */
518 public ViewPropertyAnimator rotationXBy(float value) {
519 animatePropertyBy(ROTATION_X, value);
520 return this;
521 }
522
523 /**
524 * This method will cause the View's <code>rotationY</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800525 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800526 *
527 * @param value The value to be animated to.
528 * @see View#setRotationY(float)
529 * @return This object, allowing calls to methods in this class to be chained.
530 */
531 public ViewPropertyAnimator rotationY(float value) {
532 animateProperty(ROTATION_Y, value);
533 return this;
534 }
535
536 /**
537 * This method will cause the View's <code>rotationY</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800538 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800539 *
540 * @param value The amount to be animated by, as an offset from the current value.
541 * @see View#setRotationY(float)
542 * @return This object, allowing calls to methods in this class to be chained.
543 */
544 public ViewPropertyAnimator rotationYBy(float value) {
545 animatePropertyBy(ROTATION_Y, value);
546 return this;
547 }
548
549 /**
550 * This method will cause the View's <code>translationX</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800551 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800552 *
553 * @param value The value to be animated to.
554 * @see View#setTranslationX(float)
555 * @return This object, allowing calls to methods in this class to be chained.
556 */
557 public ViewPropertyAnimator translationX(float value) {
558 animateProperty(TRANSLATION_X, value);
559 return this;
560 }
561
562 /**
563 * This method will cause the View's <code>translationX</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800564 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800565 *
566 * @param value The amount to be animated by, as an offset from the current value.
567 * @see View#setTranslationX(float)
568 * @return This object, allowing calls to methods in this class to be chained.
569 */
570 public ViewPropertyAnimator translationXBy(float value) {
571 animatePropertyBy(TRANSLATION_X, value);
572 return this;
573 }
574
575 /**
576 * This method will cause the View's <code>translationY</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800577 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800578 *
579 * @param value The value to be animated to.
580 * @see View#setTranslationY(float)
581 * @return This object, allowing calls to methods in this class to be chained.
582 */
583 public ViewPropertyAnimator translationY(float value) {
584 animateProperty(TRANSLATION_Y, value);
585 return this;
586 }
587
588 /**
589 * This method will cause the View's <code>translationY</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800590 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800591 *
592 * @param value The amount to be animated by, as an offset from the current value.
593 * @see View#setTranslationY(float)
594 * @return This object, allowing calls to methods in this class to be chained.
595 */
596 public ViewPropertyAnimator translationYBy(float value) {
597 animatePropertyBy(TRANSLATION_Y, value);
598 return this;
599 }
600
601 /**
602 * This method will cause the View's <code>scaleX</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800603 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800604 *
605 * @param value The value to be animated to.
606 * @see View#setScaleX(float)
607 * @return This object, allowing calls to methods in this class to be chained.
608 */
609 public ViewPropertyAnimator scaleX(float value) {
610 animateProperty(SCALE_X, value);
611 return this;
612 }
613
614 /**
615 * This method will cause the View's <code>scaleX</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800616 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800617 *
618 * @param value The amount to be animated by, as an offset from the current value.
619 * @see View#setScaleX(float)
620 * @return This object, allowing calls to methods in this class to be chained.
621 */
622 public ViewPropertyAnimator scaleXBy(float value) {
623 animatePropertyBy(SCALE_X, value);
624 return this;
625 }
626
627 /**
628 * This method will cause the View's <code>scaleY</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800629 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800630 *
631 * @param value The value to be animated to.
632 * @see View#setScaleY(float)
633 * @return This object, allowing calls to methods in this class to be chained.
634 */
635 public ViewPropertyAnimator scaleY(float value) {
636 animateProperty(SCALE_Y, value);
637 return this;
638 }
639
640 /**
641 * This method will cause the View's <code>scaleY</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800642 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800643 *
644 * @param value The amount to be animated by, as an offset from the current value.
645 * @see View#setScaleY(float)
646 * @return This object, allowing calls to methods in this class to be chained.
647 */
648 public ViewPropertyAnimator scaleYBy(float value) {
649 animatePropertyBy(SCALE_Y, value);
650 return this;
651 }
652
653 /**
654 * This method will cause the View's <code>alpha</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800655 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800656 *
657 * @param value The value to be animated to.
658 * @see View#setAlpha(float)
659 * @return This object, allowing calls to methods in this class to be chained.
660 */
661 public ViewPropertyAnimator alpha(float value) {
662 animateProperty(ALPHA, value);
663 return this;
664 }
665
666 /**
667 * This method will cause the View's <code>alpha</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800668 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800669 *
670 * @param value The amount to be animated by, as an offset from the current value.
671 * @see View#setAlpha(float)
672 * @return This object, allowing calls to methods in this class to be chained.
673 */
674 public ViewPropertyAnimator alphaBy(float value) {
675 animatePropertyBy(ALPHA, value);
676 return this;
677 }
678
679 /**
Chet Haasec1ca6652012-01-31 07:33:48 -0800680 * The View associated with this ViewPropertyAnimator will have its
681 * {@link View#setLayerType(int, android.graphics.Paint) layer type} set to
Chet Haasecb150fe2012-05-03 15:15:05 -0700682 * {@link View#LAYER_TYPE_HARDWARE} for the duration of the next animation.
683 * As stated in the documentation for {@link View#LAYER_TYPE_HARDWARE},
684 * the actual type of layer used internally depends on the runtime situation of the
685 * view. If the activity and this view are hardware-accelerated, then the layer will be
686 * accelerated as well. If the activity or the view is not accelerated, then the layer will
687 * effectively be the same as {@link View#LAYER_TYPE_SOFTWARE}.
688 *
689 * <p>This state is not persistent, either on the View or on this ViewPropertyAnimator: the
690 * layer type of the View will be restored when the animation ends to what it was when this
691 * method was called, and this setting on ViewPropertyAnimator is only valid for the next
692 * animation. Note that calling this method and then independently setting the layer type of
693 * the View (by a direct call to {@link View#setLayerType(int, android.graphics.Paint)}) will
694 * result in some inconsistency, including having the layer type restored to its pre-withLayer()
695 * value when the animation ends.</p>
Chet Haasec1ca6652012-01-31 07:33:48 -0800696 *
697 * @see View#setLayerType(int, android.graphics.Paint)
698 * @return This object, allowing calls to methods in this class to be chained.
699 */
700 public ViewPropertyAnimator withLayer() {
701 mPendingSetupAction= new Runnable() {
702 @Override
703 public void run() {
704 mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
Chet Haase5fd37232013-09-13 19:01:52 -0700705 if (mView.isAttachedToWindow()) {
706 mView.buildLayer();
707 }
Chet Haasec1ca6652012-01-31 07:33:48 -0800708 }
709 };
710 final int currentLayerType = mView.getLayerType();
711 mPendingCleanupAction = new Runnable() {
712 @Override
713 public void run() {
714 mView.setLayerType(currentLayerType, null);
715 }
716 };
717 if (mAnimatorSetupMap == null) {
718 mAnimatorSetupMap = new HashMap<Animator, Runnable>();
719 }
720 if (mAnimatorCleanupMap == null) {
721 mAnimatorCleanupMap = new HashMap<Animator, Runnable>();
722 }
723
724 return this;
725 }
726
727 /**
728 * Specifies an action to take place when the next animation runs. If there is a
729 * {@link #setStartDelay(long) startDelay} set on this ViewPropertyAnimator, then the
730 * action will run after that startDelay expires, when the actual animation begins.
731 * This method, along with {@link #withEndAction(Runnable)}, is intended to help facilitate
732 * choreographing ViewPropertyAnimator animations with other animations or actions
733 * in the application.
734 *
735 * @param runnable The action to run when the next animation starts.
736 * @return This object, allowing calls to methods in this class to be chained.
737 */
738 public ViewPropertyAnimator withStartAction(Runnable runnable) {
739 mPendingOnStartAction = runnable;
740 if (runnable != null && mAnimatorOnStartMap == null) {
741 mAnimatorOnStartMap = new HashMap<Animator, Runnable>();
742 }
743 return this;
744 }
745
746 /**
747 * Specifies an action to take place when the next animation ends. The action is only
748 * run if the animation ends normally; if the ViewPropertyAnimator is canceled during
749 * that animation, the runnable will not run.
750 * This method, along with {@link #withStartAction(Runnable)}, is intended to help facilitate
751 * choreographing ViewPropertyAnimator animations with other animations or actions
752 * in the application.
753 *
754 * <p>For example, the following code animates a view to x=200 and then back to 0:</p>
755 * <pre>
756 * Runnable endAction = new Runnable() {
757 * public void run() {
758 * view.animate().x(0);
759 * }
760 * };
Robert Ly8ee2a702012-12-17 15:00:08 -0800761 * view.animate().x(200).withEndAction(endAction);
Chet Haasec1ca6652012-01-31 07:33:48 -0800762 * </pre>
763 *
764 * @param runnable The action to run when the next animation ends.
765 * @return This object, allowing calls to methods in this class to be chained.
766 */
767 public ViewPropertyAnimator withEndAction(Runnable runnable) {
768 mPendingOnEndAction = runnable;
769 if (runnable != null && mAnimatorOnEndMap == null) {
770 mAnimatorOnEndMap = new HashMap<Animator, Runnable>();
771 }
772 return this;
773 }
774
775 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800776 * Starts the underlying Animator for a set of properties. We use a single animator that
777 * simply runs from 0 to 1, and then use that fractional value to set each property
778 * value accordingly.
779 */
780 private void startAnimation() {
Chet Haase563d4f22012-04-18 16:20:08 -0700781 mView.setHasTransientState(true);
Chet Haasea00f3862011-02-22 06:34:40 -0800782 ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
783 ArrayList<NameValuesHolder> nameValueList =
784 (ArrayList<NameValuesHolder>) mPendingAnimations.clone();
785 mPendingAnimations.clear();
786 int propertyMask = 0;
787 int propertyCount = nameValueList.size();
788 for (int i = 0; i < propertyCount; ++i) {
789 NameValuesHolder nameValuesHolder = nameValueList.get(i);
790 propertyMask |= nameValuesHolder.mNameConstant;
791 }
Chet Haasea00f3862011-02-22 06:34:40 -0800792 mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
Chet Haasec1ca6652012-01-31 07:33:48 -0800793 if (mPendingSetupAction != null) {
794 mAnimatorSetupMap.put(animator, mPendingSetupAction);
795 mPendingSetupAction = null;
796 }
797 if (mPendingCleanupAction != null) {
798 mAnimatorCleanupMap.put(animator, mPendingCleanupAction);
799 mPendingCleanupAction = null;
800 }
801 if (mPendingOnStartAction != null) {
802 mAnimatorOnStartMap.put(animator, mPendingOnStartAction);
803 mPendingOnStartAction = null;
804 }
805 if (mPendingOnEndAction != null) {
806 mAnimatorOnEndMap.put(animator, mPendingOnEndAction);
807 mPendingOnEndAction = null;
808 }
Chet Haasea00f3862011-02-22 06:34:40 -0800809 animator.addUpdateListener(mAnimatorEventListener);
810 animator.addListener(mAnimatorEventListener);
Chet Haasecbbd93a2011-08-08 17:34:25 -0700811 if (mStartDelaySet) {
812 animator.setStartDelay(mStartDelay);
813 }
Chet Haasea00f3862011-02-22 06:34:40 -0800814 if (mDurationSet) {
815 animator.setDuration(mDuration);
816 }
817 if (mInterpolatorSet) {
818 animator.setInterpolator(mInterpolator);
819 }
820 animator.start();
821 }
822
823 /**
824 * Utility function, called by the various x(), y(), etc. methods. This stores the
Chet Haased666cf32011-03-01 07:31:30 -0800825 * constant name for the property along with the from/delta values that will be used to
Chet Haasea00f3862011-02-22 06:34:40 -0800826 * calculate and set the property during the animation. This structure is added to the
827 * pending animations, awaiting the eventual start() of the underlying animator. A
828 * Runnable is posted to start the animation, and any pending such Runnable is canceled
829 * (which enables us to end up starting just one animator for all of the properties
830 * specified at one time).
831 *
832 * @param constantName The specifier for the property being animated
833 * @param toValue The value to which the property will animate
834 */
835 private void animateProperty(int constantName, float toValue) {
836 float fromValue = getValue(constantName);
837 float deltaValue = toValue - fromValue;
838 animatePropertyBy(constantName, fromValue, deltaValue);
839 }
840
841 /**
842 * Utility function, called by the various xBy(), yBy(), etc. methods. This method is
843 * just like animateProperty(), except the value is an offset from the property's
844 * current value, instead of an absolute "to" value.
845 *
846 * @param constantName The specifier for the property being animated
847 * @param byValue The amount by which the property will change
848 */
849 private void animatePropertyBy(int constantName, float byValue) {
850 float fromValue = getValue(constantName);
851 animatePropertyBy(constantName, fromValue, byValue);
852 }
853
854 /**
Chet Haased666cf32011-03-01 07:31:30 -0800855 * Utility function, called by animateProperty() and animatePropertyBy(), which handles the
Chet Haasea00f3862011-02-22 06:34:40 -0800856 * details of adding a pending animation and posting the request to start the animation.
857 *
858 * @param constantName The specifier for the property being animated
Chet Haased666cf32011-03-01 07:31:30 -0800859 * @param startValue The starting value of the property
Chet Haasea00f3862011-02-22 06:34:40 -0800860 * @param byValue The amount by which the property will change
861 */
Chet Haased666cf32011-03-01 07:31:30 -0800862 private void animatePropertyBy(int constantName, float startValue, float byValue) {
Chet Haaseba592d202011-02-25 11:35:17 -0800863 // First, cancel any existing animations on this property
864 if (mAnimatorMap.size() > 0) {
865 Animator animatorToCancel = null;
866 Set<Animator> animatorSet = mAnimatorMap.keySet();
867 for (Animator runningAnim : animatorSet) {
868 PropertyBundle bundle = mAnimatorMap.get(runningAnim);
869 if (bundle.cancel(constantName)) {
870 // property was canceled - cancel the animation if it's now empty
871 // Note that it's safe to break out here because every new animation
872 // on a property will cancel a previous animation on that property, so
873 // there can only ever be one such animation running.
874 if (bundle.mPropertyMask == NONE) {
Chet Haase8d5f8082011-05-24 08:03:16 -0700875 // the animation is no longer changing anything - cancel it
Chet Haaseba592d202011-02-25 11:35:17 -0800876 animatorToCancel = runningAnim;
877 break;
878 }
879 }
880 }
881 if (animatorToCancel != null) {
882 animatorToCancel.cancel();
883 }
884 }
885
Chet Haasea00f3862011-02-22 06:34:40 -0800886 NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
887 mPendingAnimations.add(nameValuePair);
Chet Haase3a000a52011-06-16 13:55:11 -0700888 mView.removeCallbacks(mAnimationStarter);
Chet Haasedcfbd6a2013-05-09 14:40:21 -0700889 mView.postOnAnimation(mAnimationStarter);
Chet Haasea00f3862011-02-22 06:34:40 -0800890 }
891
892 /**
893 * This method handles setting the property values directly in the View object's fields.
894 * propertyConstant tells it which property should be set, value is the value to set
895 * the property to.
896 *
897 * @param propertyConstant The property to be set
898 * @param value The value to set the property to
899 */
900 private void setValue(int propertyConstant, float value) {
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700901 final View.TransformationInfo info = mView.mTransformationInfo;
Chet Haase1271e2c2012-04-20 09:54:27 -0700902 final DisplayList displayList = mView.mDisplayList;
Chet Haasea00f3862011-02-22 06:34:40 -0800903 switch (propertyConstant) {
904 case TRANSLATION_X:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700905 info.mTranslationX = value;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700906 if (displayList != null) displayList.setTranslationX(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800907 break;
908 case TRANSLATION_Y:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700909 info.mTranslationY = value;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700910 if (displayList != null) displayList.setTranslationY(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800911 break;
912 case ROTATION:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700913 info.mRotation = value;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700914 if (displayList != null) displayList.setRotation(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800915 break;
916 case ROTATION_X:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700917 info.mRotationX = value;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700918 if (displayList != null) displayList.setRotationX(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800919 break;
920 case ROTATION_Y:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700921 info.mRotationY = value;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700922 if (displayList != null) displayList.setRotationY(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800923 break;
924 case SCALE_X:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700925 info.mScaleX = value;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700926 if (displayList != null) displayList.setScaleX(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800927 break;
928 case SCALE_Y:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700929 info.mScaleY = value;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700930 if (displayList != null) displayList.setScaleY(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800931 break;
932 case X:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700933 info.mTranslationX = value - mView.mLeft;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700934 if (displayList != null) displayList.setTranslationX(value - mView.mLeft);
Chet Haasea00f3862011-02-22 06:34:40 -0800935 break;
936 case Y:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700937 info.mTranslationY = value - mView.mTop;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700938 if (displayList != null) displayList.setTranslationY(value - mView.mTop);
Chet Haasea00f3862011-02-22 06:34:40 -0800939 break;
940 case ALPHA:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700941 info.mAlpha = value;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700942 if (displayList != null) displayList.setAlpha(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800943 break;
944 }
945 }
946
947 /**
948 * This method gets the value of the named property from the View object.
949 *
950 * @param propertyConstant The property whose value should be returned
951 * @return float The value of the named property
952 */
953 private float getValue(int propertyConstant) {
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700954 final View.TransformationInfo info = mView.mTransformationInfo;
Chet Haasea00f3862011-02-22 06:34:40 -0800955 switch (propertyConstant) {
956 case TRANSLATION_X:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700957 return info.mTranslationX;
Chet Haasea00f3862011-02-22 06:34:40 -0800958 case TRANSLATION_Y:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700959 return info.mTranslationY;
Chet Haasea00f3862011-02-22 06:34:40 -0800960 case ROTATION:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700961 return info.mRotation;
Chet Haasea00f3862011-02-22 06:34:40 -0800962 case ROTATION_X:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700963 return info.mRotationX;
Chet Haasea00f3862011-02-22 06:34:40 -0800964 case ROTATION_Y:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700965 return info.mRotationY;
Chet Haasea00f3862011-02-22 06:34:40 -0800966 case SCALE_X:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700967 return info.mScaleX;
Chet Haasea00f3862011-02-22 06:34:40 -0800968 case SCALE_Y:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700969 return info.mScaleY;
Chet Haasea00f3862011-02-22 06:34:40 -0800970 case X:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700971 return mView.mLeft + info.mTranslationX;
Chet Haasea00f3862011-02-22 06:34:40 -0800972 case Y:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700973 return mView.mTop + info.mTranslationY;
Chet Haasea00f3862011-02-22 06:34:40 -0800974 case ALPHA:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700975 return info.mAlpha;
Chet Haasea00f3862011-02-22 06:34:40 -0800976 }
977 return 0;
978 }
979
980 /**
981 * Utility class that handles the various Animator events. The only ones we care
982 * about are the end event (which we use to clean up the animator map when an animator
983 * finishes) and the update event (which we use to calculate the current value of each
984 * property and then set it on the view object).
985 */
986 private class AnimatorEventListener
987 implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
988 @Override
989 public void onAnimationStart(Animator animation) {
Chet Haasec1ca6652012-01-31 07:33:48 -0800990 if (mAnimatorSetupMap != null) {
991 Runnable r = mAnimatorSetupMap.get(animation);
992 if (r != null) {
993 r.run();
994 }
995 mAnimatorSetupMap.remove(animation);
996 }
997 if (mAnimatorOnStartMap != null) {
998 Runnable r = mAnimatorOnStartMap.get(animation);
999 if (r != null) {
1000 r.run();
1001 }
1002 mAnimatorOnStartMap.remove(animation);
1003 }
Chet Haasea00f3862011-02-22 06:34:40 -08001004 if (mListener != null) {
1005 mListener.onAnimationStart(animation);
1006 }
1007 }
1008
1009 @Override
1010 public void onAnimationCancel(Animator animation) {
1011 if (mListener != null) {
1012 mListener.onAnimationCancel(animation);
1013 }
Chet Haasec1ca6652012-01-31 07:33:48 -08001014 if (mAnimatorOnEndMap != null) {
1015 mAnimatorOnEndMap.remove(animation);
1016 }
Chet Haasea00f3862011-02-22 06:34:40 -08001017 }
1018
1019 @Override
1020 public void onAnimationRepeat(Animator animation) {
1021 if (mListener != null) {
1022 mListener.onAnimationRepeat(animation);
1023 }
1024 }
1025
1026 @Override
1027 public void onAnimationEnd(Animator animation) {
Chet Haase563d4f22012-04-18 16:20:08 -07001028 mView.setHasTransientState(false);
Chet Haasea00f3862011-02-22 06:34:40 -08001029 if (mListener != null) {
1030 mListener.onAnimationEnd(animation);
1031 }
Chet Haasec1ca6652012-01-31 07:33:48 -08001032 if (mAnimatorOnEndMap != null) {
1033 Runnable r = mAnimatorOnEndMap.get(animation);
1034 if (r != null) {
1035 r.run();
1036 }
1037 mAnimatorOnEndMap.remove(animation);
1038 }
1039 if (mAnimatorCleanupMap != null) {
1040 Runnable r = mAnimatorCleanupMap.get(animation);
1041 if (r != null) {
1042 r.run();
1043 }
1044 mAnimatorCleanupMap.remove(animation);
1045 }
Chet Haasea00f3862011-02-22 06:34:40 -08001046 mAnimatorMap.remove(animation);
1047 }
1048
1049 /**
1050 * Calculate the current value for each property and set it on the view. Invalidate
1051 * the view object appropriately, depending on which properties are being animated.
1052 *
1053 * @param animation The animator associated with the properties that need to be
1054 * set. This animator holds the animation fraction which we will use to calculate
1055 * the current value of each property.
1056 */
1057 @Override
1058 public void onAnimationUpdate(ValueAnimator animation) {
Chet Haase0c6d83cc2011-12-01 08:38:13 -08001059 PropertyBundle propertyBundle = mAnimatorMap.get(animation);
1060 if (propertyBundle == null) {
1061 // Shouldn't happen, but just to play it safe
1062 return;
1063 }
Chet Haase1271e2c2012-04-20 09:54:27 -07001064 boolean useDisplayListProperties = mView.mDisplayList != null;
Chet Haase9d1992d2012-03-13 11:03:25 -07001065
Chet Haasea00f3862011-02-22 06:34:40 -08001066 // alpha requires slightly different treatment than the other (transform) properties.
1067 // The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
1068 // logic is dependent on how the view handles an internal call to onSetAlpha().
1069 // We track what kinds of properties are set, and how alpha is handled when it is
1070 // set, and perform the invalidation steps appropriately.
1071 boolean alphaHandled = false;
Chet Haase9d1992d2012-03-13 11:03:25 -07001072 if (!useDisplayListProperties) {
1073 mView.invalidateParentCaches();
1074 }
Chet Haasea00f3862011-02-22 06:34:40 -08001075 float fraction = animation.getAnimatedFraction();
Chet Haasea00f3862011-02-22 06:34:40 -08001076 int propertyMask = propertyBundle.mPropertyMask;
1077 if ((propertyMask & TRANSFORM_MASK) != 0) {
Chet Haase9d1992d2012-03-13 11:03:25 -07001078 mView.invalidateViewProperty(false, false);
Chet Haasea00f3862011-02-22 06:34:40 -08001079 }
1080 ArrayList<NameValuesHolder> valueList = propertyBundle.mNameValuesHolder;
1081 if (valueList != null) {
1082 int count = valueList.size();
1083 for (int i = 0; i < count; ++i) {
1084 NameValuesHolder values = valueList.get(i);
1085 float value = values.mFromValue + fraction * values.mDeltaValue;
1086 if (values.mNameConstant == ALPHA) {
1087 alphaHandled = mView.setAlphaNoInvalidation(value);
1088 } else {
1089 setValue(values.mNameConstant, value);
1090 }
1091 }
1092 }
1093 if ((propertyMask & TRANSFORM_MASK) != 0) {
Dianne Hackbornddb715b2011-09-09 14:43:39 -07001094 mView.mTransformationInfo.mMatrixDirty = true;
Chet Haase9d1992d2012-03-13 11:03:25 -07001095 if (!useDisplayListProperties) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001096 mView.mPrivateFlags |= View.PFLAG_DRAWN; // force another invalidation
Chet Haase9d1992d2012-03-13 11:03:25 -07001097 }
Chet Haasea00f3862011-02-22 06:34:40 -08001098 }
1099 // invalidate(false) in all cases except if alphaHandled gets set to true
1100 // via the call to setAlphaNoInvalidation(), above
Chet Haase9d1992d2012-03-13 11:03:25 -07001101 if (alphaHandled) {
1102 mView.invalidate(true);
1103 } else {
1104 mView.invalidateViewProperty(false, false);
1105 }
Chet Haase87f4ae62013-09-06 18:29:56 -07001106 if (mUpdateListener != null) {
1107 mUpdateListener.onAnimationUpdate(animation);
1108 }
Chet Haasea00f3862011-02-22 06:34:40 -08001109 }
1110 }
1111}