blob: 1892aa7d1b78b9acc80b408c7dccc3d894860a8a [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;
Chris Craikd863a102013-12-19 13:31:15 -0800139 private static final int TRANSLATION_Z = 0x0004;
140 private static final int SCALE_X = 0x0008;
141 private static final int SCALE_Y = 0x0010;
142 private static final int ROTATION = 0x0020;
143 private static final int ROTATION_X = 0x0040;
144 private static final int ROTATION_Y = 0x0080;
145 private static final int X = 0x0100;
146 private static final int Y = 0x0200;
147 private static final int ALPHA = 0x0400;
Chet Haasea00f3862011-02-22 06:34:40 -0800148
Chris Craikf57776b2013-10-25 18:30:17 -0700149 private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | TRANSLATION_Z |
150 SCALE_X | SCALE_Y | ROTATION | ROTATION_X | ROTATION_Y | X | Y;
Chet Haasea00f3862011-02-22 06:34:40 -0800151
152 /**
153 * The mechanism by which the user can request several properties that are then animated
154 * together works by posting this Runnable to start the underlying Animator. Every time
155 * a property animation is requested, we cancel any previous postings of the Runnable
156 * and re-post it. This means that we will only ever run the Runnable (and thus start the
157 * underlying animator) after the caller is done setting the properties that should be
158 * animated together.
159 */
160 private Runnable mAnimationStarter = new Runnable() {
161 @Override
162 public void run() {
163 startAnimation();
164 }
165 };
166
167 /**
168 * This class holds information about the overall animation being run on the set of
169 * properties. The mask describes which properties are being animated and the
170 * values holder is the list of all property/value objects.
171 */
172 private static class PropertyBundle {
173 int mPropertyMask;
174 ArrayList<NameValuesHolder> mNameValuesHolder;
Chet Haaseba592d202011-02-25 11:35:17 -0800175
Chet Haasea00f3862011-02-22 06:34:40 -0800176 PropertyBundle(int propertyMask, ArrayList<NameValuesHolder> nameValuesHolder) {
177 mPropertyMask = propertyMask;
178 mNameValuesHolder = nameValuesHolder;
179 }
Chet Haaseba592d202011-02-25 11:35:17 -0800180
181 /**
182 * Removes the given property from being animated as a part of this
183 * PropertyBundle. If the property was a part of this bundle, it returns
184 * true to indicate that it was, in fact, canceled. This is an indication
185 * to the caller that a cancellation actually occurred.
186 *
187 * @param propertyConstant The property whose cancellation is requested.
188 * @return true if the given property is a part of this bundle and if it
189 * has therefore been canceled.
190 */
191 boolean cancel(int propertyConstant) {
192 if ((mPropertyMask & propertyConstant) != 0 && mNameValuesHolder != null) {
193 int count = mNameValuesHolder.size();
194 for (int i = 0; i < count; ++i) {
195 NameValuesHolder nameValuesHolder = mNameValuesHolder.get(i);
196 if (nameValuesHolder.mNameConstant == propertyConstant) {
197 mNameValuesHolder.remove(i);
198 mPropertyMask &= ~propertyConstant;
199 return true;
200 }
201 }
202 }
203 return false;
204 }
Chet Haasea00f3862011-02-22 06:34:40 -0800205 }
206
207 /**
208 * This list tracks the list of properties being animated by any particular animator.
209 * In most situations, there would only ever be one animator running at a time. But it is
210 * possible to request some properties to animate together, then while those properties
211 * are animating, to request some other properties to animate together. The way that
212 * works is by having this map associate the group of properties being animated with the
213 * animator handling the animation. On every update event for an Animator, we ask the
214 * map for the associated properties and set them accordingly.
215 */
216 private HashMap<Animator, PropertyBundle> mAnimatorMap =
217 new HashMap<Animator, PropertyBundle>();
Chet Haasec1ca6652012-01-31 07:33:48 -0800218 private HashMap<Animator, Runnable> mAnimatorSetupMap;
219 private HashMap<Animator, Runnable> mAnimatorCleanupMap;
220 private HashMap<Animator, Runnable> mAnimatorOnStartMap;
221 private HashMap<Animator, Runnable> mAnimatorOnEndMap;
Chet Haasea00f3862011-02-22 06:34:40 -0800222
223 /**
224 * This is the information we need to set each property during the animation.
225 * mNameConstant is used to set the appropriate field in View, and the from/delta
226 * values are used to calculate the animated value for a given animation fraction
227 * during the animation.
228 */
229 private static class NameValuesHolder {
230 int mNameConstant;
231 float mFromValue;
232 float mDeltaValue;
233 NameValuesHolder(int nameConstant, float fromValue, float deltaValue) {
234 mNameConstant = nameConstant;
235 mFromValue = fromValue;
236 mDeltaValue = deltaValue;
237 }
238 }
239
240 /**
241 * Constructor, called by View. This is private by design, as the user should only
242 * get a ViewPropertyAnimator by calling View.animate().
243 *
244 * @param view The View associated with this ViewPropertyAnimator
245 */
246 ViewPropertyAnimator(View view) {
247 mView = view;
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700248 view.ensureTransformationInfo();
Chet Haasea00f3862011-02-22 06:34:40 -0800249 }
250
251 /**
252 * Sets the duration for the underlying animator that animates the requested properties.
253 * By default, the animator uses the default value for ValueAnimator. Calling this method
254 * will cause the declared value to be used instead.
255 * @param duration The length of ensuing property animations, in milliseconds. The value
256 * cannot be negative.
257 * @return This object, allowing calls to methods in this class to be chained.
258 */
259 public ViewPropertyAnimator setDuration(long duration) {
260 if (duration < 0) {
261 throw new IllegalArgumentException("Animators cannot have negative duration: " +
262 duration);
263 }
264 mDurationSet = true;
265 mDuration = duration;
266 return this;
267 }
268
269 /**
Chet Haase8d5f8082011-05-24 08:03:16 -0700270 * Returns the current duration of property animations. If the duration was set on this
271 * object, that value is returned. Otherwise, the default value of the underlying Animator
272 * is returned.
273 *
274 * @see #setDuration(long)
275 * @return The duration of animations, in milliseconds.
276 */
277 public long getDuration() {
Chet Haasecbbd93a2011-08-08 17:34:25 -0700278 if (mDurationSet) {
279 return mDuration;
Chet Haase8d5f8082011-05-24 08:03:16 -0700280 } else {
281 // Just return the default from ValueAnimator, since that's what we'd get if
282 // the value has not been set otherwise
Cyril Mottierd40acfb2013-07-25 10:08:29 +0200283 if (mTempValueAnimator == null) {
284 mTempValueAnimator = new ValueAnimator();
285 }
286 return mTempValueAnimator.getDuration();
Chet Haase8d5f8082011-05-24 08:03:16 -0700287 }
288 }
289
290 /**
291 * Returns the current startDelay of property animations. If the startDelay was set on this
292 * object, that value is returned. Otherwise, the default value of the underlying Animator
293 * is returned.
294 *
295 * @see #setStartDelay(long)
296 * @return The startDelay of animations, in milliseconds.
297 */
298 public long getStartDelay() {
299 if (mStartDelaySet) {
300 return mStartDelay;
301 } else {
302 // Just return the default from ValueAnimator (0), since that's what we'd get if
303 // the value has not been set otherwise
304 return 0;
305 }
306 }
307
308 /**
309 * Sets the startDelay for the underlying animator that animates the requested properties.
310 * By default, the animator uses the default value for ValueAnimator. Calling this method
311 * will cause the declared value to be used instead.
312 * @param startDelay The delay of ensuing property animations, in milliseconds. The value
313 * cannot be negative.
314 * @return This object, allowing calls to methods in this class to be chained.
315 */
316 public ViewPropertyAnimator setStartDelay(long startDelay) {
317 if (startDelay < 0) {
318 throw new IllegalArgumentException("Animators cannot have negative duration: " +
319 startDelay);
320 }
321 mStartDelaySet = true;
322 mStartDelay = startDelay;
323 return this;
324 }
325
326 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800327 * Sets the interpolator for the underlying animator that animates the requested properties.
328 * By default, the animator uses the default interpolator for ValueAnimator. Calling this method
329 * will cause the declared object to be used instead.
330 *
331 * @param interpolator The TimeInterpolator to be used for ensuing property animations.
332 * @return This object, allowing calls to methods in this class to be chained.
333 */
334 public ViewPropertyAnimator setInterpolator(TimeInterpolator interpolator) {
335 mInterpolatorSet = true;
336 mInterpolator = interpolator;
337 return this;
338 }
339
340 /**
Chet Haase430742f2013-04-12 11:18:36 -0700341 * Returns the timing interpolator that this animation uses.
342 *
343 * @return The timing interpolator for this animation.
344 */
345 public TimeInterpolator getInterpolator() {
Cyril Mottierd40acfb2013-07-25 10:08:29 +0200346 if (mInterpolatorSet) {
347 return mInterpolator;
348 } else {
349 // Just return the default from ValueAnimator, since that's what we'd get if
350 // the value has not been set otherwise
351 if (mTempValueAnimator == null) {
352 mTempValueAnimator = new ValueAnimator();
353 }
354 return mTempValueAnimator.getInterpolator();
355 }
Chet Haase430742f2013-04-12 11:18:36 -0700356 }
357
358 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800359 * Sets a listener for events in the underlying Animators that run the property
360 * animations.
361 *
Chet Haase87f4ae62013-09-06 18:29:56 -0700362 * @see Animator.AnimatorListener
363 *
364 * @param listener The listener to be called with AnimatorListener events. A value of
365 * <code>null</code> removes any existing listener.
Chet Haasea00f3862011-02-22 06:34:40 -0800366 * @return This object, allowing calls to methods in this class to be chained.
367 */
368 public ViewPropertyAnimator setListener(Animator.AnimatorListener listener) {
369 mListener = listener;
370 return this;
371 }
372
373 /**
Chet Haase87f4ae62013-09-06 18:29:56 -0700374 * Sets a listener for update events in the underlying ValueAnimator that runs
375 * the property animations. Note that the underlying animator is animating between
376 * 0 and 1 (these values are then turned into the actual property values internally
377 * by ViewPropertyAnimator). So the animator cannot give information on the current
378 * values of the properties being animated by this ViewPropertyAnimator, although
379 * the view object itself can be queried to get the current values.
380 *
381 * @see android.animation.ValueAnimator.AnimatorUpdateListener
382 *
383 * @param listener The listener to be called with update events. A value of
384 * <code>null</code> removes any existing listener.
385 * @return This object, allowing calls to methods in this class to be chained.
386 */
387 public ViewPropertyAnimator setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) {
388 mUpdateListener = listener;
389 return this;
390 }
391
392 /**
Chet Haase8d5f8082011-05-24 08:03:16 -0700393 * Starts the currently pending property animations immediately. Calling <code>start()</code>
394 * is optional because all animations start automatically at the next opportunity. However,
395 * if the animations are needed to start immediately and synchronously (not at the time when
396 * the next event is processed by the hierarchy, which is when the animations would begin
397 * otherwise), then this method can be used.
398 */
399 public void start() {
Michael Jurka500998d2012-05-13 15:35:02 -0700400 mView.removeCallbacks(mAnimationStarter);
Chet Haase8d5f8082011-05-24 08:03:16 -0700401 startAnimation();
402 }
403
404 /**
405 * Cancels all property animations that are currently running or pending.
406 */
407 public void cancel() {
408 if (mAnimatorMap.size() > 0) {
409 HashMap<Animator, PropertyBundle> mAnimatorMapCopy =
410 (HashMap<Animator, PropertyBundle>)mAnimatorMap.clone();
411 Set<Animator> animatorSet = mAnimatorMapCopy.keySet();
412 for (Animator runningAnim : animatorSet) {
413 runningAnim.cancel();
414 }
415 }
416 mPendingAnimations.clear();
Chet Haase3a000a52011-06-16 13:55:11 -0700417 mView.removeCallbacks(mAnimationStarter);
Chet Haase8d5f8082011-05-24 08:03:16 -0700418 }
419
420 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800421 * This method will cause the View's <code>x</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800422 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800423 *
424 * @param value The value to be animated to.
425 * @see View#setX(float)
426 * @return This object, allowing calls to methods in this class to be chained.
427 */
428 public ViewPropertyAnimator x(float value) {
429 animateProperty(X, value);
430 return this;
431 }
432
433 /**
434 * This method will cause the View's <code>x</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800435 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800436 *
437 * @param value The amount to be animated by, as an offset from the current value.
438 * @see View#setX(float)
439 * @return This object, allowing calls to methods in this class to be chained.
440 */
441 public ViewPropertyAnimator xBy(float value) {
442 animatePropertyBy(X, value);
443 return this;
444 }
445
446 /**
447 * This method will cause the View's <code>y</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800448 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800449 *
450 * @param value The value to be animated to.
451 * @see View#setY(float)
452 * @return This object, allowing calls to methods in this class to be chained.
453 */
454 public ViewPropertyAnimator y(float value) {
455 animateProperty(Y, value);
456 return this;
457 }
458
459 /**
460 * This method will cause the View's <code>y</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800461 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800462 *
463 * @param value The amount to be animated by, as an offset from the current value.
464 * @see View#setY(float)
465 * @return This object, allowing calls to methods in this class to be chained.
466 */
467 public ViewPropertyAnimator yBy(float value) {
468 animatePropertyBy(Y, value);
469 return this;
470 }
471
472 /**
473 * This method will cause the View's <code>rotation</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800474 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800475 *
476 * @param value The value to be animated to.
477 * @see View#setRotation(float)
478 * @return This object, allowing calls to methods in this class to be chained.
479 */
480 public ViewPropertyAnimator rotation(float value) {
481 animateProperty(ROTATION, value);
482 return this;
483 }
484
485 /**
486 * This method will cause the View's <code>rotation</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800487 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800488 *
489 * @param value The amount to be animated by, as an offset from the current value.
490 * @see View#setRotation(float)
491 * @return This object, allowing calls to methods in this class to be chained.
492 */
493 public ViewPropertyAnimator rotationBy(float value) {
494 animatePropertyBy(ROTATION, value);
495 return this;
496 }
497
498 /**
499 * This method will cause the View's <code>rotationX</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800500 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800501 *
502 * @param value The value to be animated to.
503 * @see View#setRotationX(float)
504 * @return This object, allowing calls to methods in this class to be chained.
505 */
506 public ViewPropertyAnimator rotationX(float value) {
507 animateProperty(ROTATION_X, value);
508 return this;
509 }
510
511 /**
512 * This method will cause the View's <code>rotationX</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800513 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800514 *
515 * @param value The amount to be animated by, as an offset from the current value.
516 * @see View#setRotationX(float)
517 * @return This object, allowing calls to methods in this class to be chained.
518 */
519 public ViewPropertyAnimator rotationXBy(float value) {
520 animatePropertyBy(ROTATION_X, value);
521 return this;
522 }
523
524 /**
525 * This method will cause the View's <code>rotationY</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800526 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800527 *
528 * @param value The value to be animated to.
529 * @see View#setRotationY(float)
530 * @return This object, allowing calls to methods in this class to be chained.
531 */
532 public ViewPropertyAnimator rotationY(float value) {
533 animateProperty(ROTATION_Y, value);
534 return this;
535 }
536
537 /**
538 * This method will cause the View's <code>rotationY</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800539 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800540 *
541 * @param value The amount to be animated by, as an offset from the current value.
542 * @see View#setRotationY(float)
543 * @return This object, allowing calls to methods in this class to be chained.
544 */
545 public ViewPropertyAnimator rotationYBy(float value) {
546 animatePropertyBy(ROTATION_Y, value);
547 return this;
548 }
549
550 /**
551 * This method will cause the View's <code>translationX</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800552 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800553 *
554 * @param value The value to be animated to.
555 * @see View#setTranslationX(float)
556 * @return This object, allowing calls to methods in this class to be chained.
557 */
558 public ViewPropertyAnimator translationX(float value) {
559 animateProperty(TRANSLATION_X, value);
560 return this;
561 }
562
563 /**
564 * This method will cause the View's <code>translationX</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800565 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800566 *
567 * @param value The amount to be animated by, as an offset from the current value.
568 * @see View#setTranslationX(float)
569 * @return This object, allowing calls to methods in this class to be chained.
570 */
571 public ViewPropertyAnimator translationXBy(float value) {
572 animatePropertyBy(TRANSLATION_X, value);
573 return this;
574 }
575
576 /**
577 * This method will cause the View's <code>translationY</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800578 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800579 *
580 * @param value The value to be animated to.
581 * @see View#setTranslationY(float)
582 * @return This object, allowing calls to methods in this class to be chained.
583 */
584 public ViewPropertyAnimator translationY(float value) {
585 animateProperty(TRANSLATION_Y, value);
586 return this;
587 }
588
589 /**
590 * This method will cause the View's <code>translationY</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800591 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800592 *
593 * @param value The amount to be animated by, as an offset from the current value.
594 * @see View#setTranslationY(float)
595 * @return This object, allowing calls to methods in this class to be chained.
596 */
597 public ViewPropertyAnimator translationYBy(float value) {
598 animatePropertyBy(TRANSLATION_Y, value);
599 return this;
600 }
601
602 /**
Chris Craikd863a102013-12-19 13:31:15 -0800603 * This method will cause the View's <code>translationZ</code> property to be animated to the
604 * specified value. Animations already running on the property will be canceled.
605 *
606 * @param value The value to be animated to.
607 * @see View#setTranslationZ(float)
608 * @return This object, allowing calls to methods in this class to be chained.
609 */
610 public ViewPropertyAnimator translationZ(float value) {
611 animateProperty(TRANSLATION_Z, value);
612 return this;
613 }
614
615 /**
616 * This method will cause the View's <code>translationZ</code> property to be animated by the
617 * specified value. Animations already running on the property will be canceled.
618 *
619 * @param value The amount to be animated by, as an offset from the current value.
620 * @see View#setTranslationZ(float)
621 * @return This object, allowing calls to methods in this class to be chained.
622 */
623 public ViewPropertyAnimator translationZBy(float value) {
624 animatePropertyBy(TRANSLATION_Z, value);
625 return this;
626 }
627 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800628 * This method will cause the View's <code>scaleX</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#setScaleX(float)
633 * @return This object, allowing calls to methods in this class to be chained.
634 */
635 public ViewPropertyAnimator scaleX(float value) {
636 animateProperty(SCALE_X, value);
637 return this;
638 }
639
640 /**
641 * This method will cause the View's <code>scaleX</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#setScaleX(float)
646 * @return This object, allowing calls to methods in this class to be chained.
647 */
648 public ViewPropertyAnimator scaleXBy(float value) {
649 animatePropertyBy(SCALE_X, value);
650 return this;
651 }
652
653 /**
654 * This method will cause the View's <code>scaleY</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#setScaleY(float)
659 * @return This object, allowing calls to methods in this class to be chained.
660 */
661 public ViewPropertyAnimator scaleY(float value) {
662 animateProperty(SCALE_Y, value);
663 return this;
664 }
665
666 /**
667 * This method will cause the View's <code>scaleY</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#setScaleY(float)
672 * @return This object, allowing calls to methods in this class to be chained.
673 */
674 public ViewPropertyAnimator scaleYBy(float value) {
675 animatePropertyBy(SCALE_Y, value);
676 return this;
677 }
678
679 /**
680 * This method will cause the View's <code>alpha</code> property to be animated to the
Chet Haased666cf32011-03-01 07:31:30 -0800681 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800682 *
683 * @param value The value to be animated to.
684 * @see View#setAlpha(float)
685 * @return This object, allowing calls to methods in this class to be chained.
686 */
687 public ViewPropertyAnimator alpha(float value) {
688 animateProperty(ALPHA, value);
689 return this;
690 }
691
692 /**
693 * This method will cause the View's <code>alpha</code> property to be animated by the
Chet Haased666cf32011-03-01 07:31:30 -0800694 * specified value. Animations already running on the property will be canceled.
Chet Haasea00f3862011-02-22 06:34:40 -0800695 *
696 * @param value The amount to be animated by, as an offset from the current value.
697 * @see View#setAlpha(float)
698 * @return This object, allowing calls to methods in this class to be chained.
699 */
700 public ViewPropertyAnimator alphaBy(float value) {
701 animatePropertyBy(ALPHA, value);
702 return this;
703 }
704
705 /**
Chet Haasec1ca6652012-01-31 07:33:48 -0800706 * The View associated with this ViewPropertyAnimator will have its
707 * {@link View#setLayerType(int, android.graphics.Paint) layer type} set to
Chet Haasecb150fe2012-05-03 15:15:05 -0700708 * {@link View#LAYER_TYPE_HARDWARE} for the duration of the next animation.
709 * As stated in the documentation for {@link View#LAYER_TYPE_HARDWARE},
710 * the actual type of layer used internally depends on the runtime situation of the
711 * view. If the activity and this view are hardware-accelerated, then the layer will be
712 * accelerated as well. If the activity or the view is not accelerated, then the layer will
713 * effectively be the same as {@link View#LAYER_TYPE_SOFTWARE}.
714 *
715 * <p>This state is not persistent, either on the View or on this ViewPropertyAnimator: the
716 * layer type of the View will be restored when the animation ends to what it was when this
717 * method was called, and this setting on ViewPropertyAnimator is only valid for the next
718 * animation. Note that calling this method and then independently setting the layer type of
719 * the View (by a direct call to {@link View#setLayerType(int, android.graphics.Paint)}) will
720 * result in some inconsistency, including having the layer type restored to its pre-withLayer()
721 * value when the animation ends.</p>
Chet Haasec1ca6652012-01-31 07:33:48 -0800722 *
723 * @see View#setLayerType(int, android.graphics.Paint)
724 * @return This object, allowing calls to methods in this class to be chained.
725 */
726 public ViewPropertyAnimator withLayer() {
727 mPendingSetupAction= new Runnable() {
728 @Override
729 public void run() {
730 mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
Chet Haase5fd37232013-09-13 19:01:52 -0700731 if (mView.isAttachedToWindow()) {
732 mView.buildLayer();
733 }
Chet Haasec1ca6652012-01-31 07:33:48 -0800734 }
735 };
736 final int currentLayerType = mView.getLayerType();
737 mPendingCleanupAction = new Runnable() {
738 @Override
739 public void run() {
740 mView.setLayerType(currentLayerType, null);
741 }
742 };
743 if (mAnimatorSetupMap == null) {
744 mAnimatorSetupMap = new HashMap<Animator, Runnable>();
745 }
746 if (mAnimatorCleanupMap == null) {
747 mAnimatorCleanupMap = new HashMap<Animator, Runnable>();
748 }
749
750 return this;
751 }
752
753 /**
754 * Specifies an action to take place when the next animation runs. If there is a
755 * {@link #setStartDelay(long) startDelay} set on this ViewPropertyAnimator, then the
756 * action will run after that startDelay expires, when the actual animation begins.
757 * This method, along with {@link #withEndAction(Runnable)}, is intended to help facilitate
758 * choreographing ViewPropertyAnimator animations with other animations or actions
759 * in the application.
760 *
761 * @param runnable The action to run when the next animation starts.
762 * @return This object, allowing calls to methods in this class to be chained.
763 */
764 public ViewPropertyAnimator withStartAction(Runnable runnable) {
765 mPendingOnStartAction = runnable;
766 if (runnable != null && mAnimatorOnStartMap == null) {
767 mAnimatorOnStartMap = new HashMap<Animator, Runnable>();
768 }
769 return this;
770 }
771
772 /**
773 * Specifies an action to take place when the next animation ends. The action is only
774 * run if the animation ends normally; if the ViewPropertyAnimator is canceled during
775 * that animation, the runnable will not run.
776 * This method, along with {@link #withStartAction(Runnable)}, is intended to help facilitate
777 * choreographing ViewPropertyAnimator animations with other animations or actions
778 * in the application.
779 *
780 * <p>For example, the following code animates a view to x=200 and then back to 0:</p>
781 * <pre>
782 * Runnable endAction = new Runnable() {
783 * public void run() {
784 * view.animate().x(0);
785 * }
786 * };
Robert Ly8ee2a702012-12-17 15:00:08 -0800787 * view.animate().x(200).withEndAction(endAction);
Chet Haasec1ca6652012-01-31 07:33:48 -0800788 * </pre>
789 *
790 * @param runnable The action to run when the next animation ends.
791 * @return This object, allowing calls to methods in this class to be chained.
792 */
793 public ViewPropertyAnimator withEndAction(Runnable runnable) {
794 mPendingOnEndAction = runnable;
795 if (runnable != null && mAnimatorOnEndMap == null) {
796 mAnimatorOnEndMap = new HashMap<Animator, Runnable>();
797 }
798 return this;
799 }
800
801 /**
Chet Haasea00f3862011-02-22 06:34:40 -0800802 * Starts the underlying Animator for a set of properties. We use a single animator that
803 * simply runs from 0 to 1, and then use that fractional value to set each property
804 * value accordingly.
805 */
806 private void startAnimation() {
Chet Haase563d4f22012-04-18 16:20:08 -0700807 mView.setHasTransientState(true);
Chet Haasea00f3862011-02-22 06:34:40 -0800808 ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
809 ArrayList<NameValuesHolder> nameValueList =
810 (ArrayList<NameValuesHolder>) mPendingAnimations.clone();
811 mPendingAnimations.clear();
812 int propertyMask = 0;
813 int propertyCount = nameValueList.size();
814 for (int i = 0; i < propertyCount; ++i) {
815 NameValuesHolder nameValuesHolder = nameValueList.get(i);
816 propertyMask |= nameValuesHolder.mNameConstant;
817 }
Chet Haasea00f3862011-02-22 06:34:40 -0800818 mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
Chet Haasec1ca6652012-01-31 07:33:48 -0800819 if (mPendingSetupAction != null) {
820 mAnimatorSetupMap.put(animator, mPendingSetupAction);
821 mPendingSetupAction = null;
822 }
823 if (mPendingCleanupAction != null) {
824 mAnimatorCleanupMap.put(animator, mPendingCleanupAction);
825 mPendingCleanupAction = null;
826 }
827 if (mPendingOnStartAction != null) {
828 mAnimatorOnStartMap.put(animator, mPendingOnStartAction);
829 mPendingOnStartAction = null;
830 }
831 if (mPendingOnEndAction != null) {
832 mAnimatorOnEndMap.put(animator, mPendingOnEndAction);
833 mPendingOnEndAction = null;
834 }
Chet Haasea00f3862011-02-22 06:34:40 -0800835 animator.addUpdateListener(mAnimatorEventListener);
836 animator.addListener(mAnimatorEventListener);
Chet Haasecbbd93a2011-08-08 17:34:25 -0700837 if (mStartDelaySet) {
838 animator.setStartDelay(mStartDelay);
839 }
Chet Haasea00f3862011-02-22 06:34:40 -0800840 if (mDurationSet) {
841 animator.setDuration(mDuration);
842 }
843 if (mInterpolatorSet) {
844 animator.setInterpolator(mInterpolator);
845 }
846 animator.start();
847 }
848
849 /**
850 * Utility function, called by the various x(), y(), etc. methods. This stores the
Chet Haased666cf32011-03-01 07:31:30 -0800851 * constant name for the property along with the from/delta values that will be used to
Chet Haasea00f3862011-02-22 06:34:40 -0800852 * calculate and set the property during the animation. This structure is added to the
853 * pending animations, awaiting the eventual start() of the underlying animator. A
854 * Runnable is posted to start the animation, and any pending such Runnable is canceled
855 * (which enables us to end up starting just one animator for all of the properties
856 * specified at one time).
857 *
858 * @param constantName The specifier for the property being animated
859 * @param toValue The value to which the property will animate
860 */
861 private void animateProperty(int constantName, float toValue) {
862 float fromValue = getValue(constantName);
863 float deltaValue = toValue - fromValue;
864 animatePropertyBy(constantName, fromValue, deltaValue);
865 }
866
867 /**
868 * Utility function, called by the various xBy(), yBy(), etc. methods. This method is
869 * just like animateProperty(), except the value is an offset from the property's
870 * current value, instead of an absolute "to" value.
871 *
872 * @param constantName The specifier for the property being animated
873 * @param byValue The amount by which the property will change
874 */
875 private void animatePropertyBy(int constantName, float byValue) {
876 float fromValue = getValue(constantName);
877 animatePropertyBy(constantName, fromValue, byValue);
878 }
879
880 /**
Chet Haased666cf32011-03-01 07:31:30 -0800881 * Utility function, called by animateProperty() and animatePropertyBy(), which handles the
Chet Haasea00f3862011-02-22 06:34:40 -0800882 * details of adding a pending animation and posting the request to start the animation.
883 *
884 * @param constantName The specifier for the property being animated
Chet Haased666cf32011-03-01 07:31:30 -0800885 * @param startValue The starting value of the property
Chet Haasea00f3862011-02-22 06:34:40 -0800886 * @param byValue The amount by which the property will change
887 */
Chet Haased666cf32011-03-01 07:31:30 -0800888 private void animatePropertyBy(int constantName, float startValue, float byValue) {
Chet Haaseba592d202011-02-25 11:35:17 -0800889 // First, cancel any existing animations on this property
890 if (mAnimatorMap.size() > 0) {
891 Animator animatorToCancel = null;
892 Set<Animator> animatorSet = mAnimatorMap.keySet();
893 for (Animator runningAnim : animatorSet) {
894 PropertyBundle bundle = mAnimatorMap.get(runningAnim);
895 if (bundle.cancel(constantName)) {
896 // property was canceled - cancel the animation if it's now empty
897 // Note that it's safe to break out here because every new animation
898 // on a property will cancel a previous animation on that property, so
899 // there can only ever be one such animation running.
900 if (bundle.mPropertyMask == NONE) {
Chet Haase8d5f8082011-05-24 08:03:16 -0700901 // the animation is no longer changing anything - cancel it
Chet Haaseba592d202011-02-25 11:35:17 -0800902 animatorToCancel = runningAnim;
903 break;
904 }
905 }
906 }
907 if (animatorToCancel != null) {
908 animatorToCancel.cancel();
909 }
910 }
911
Chet Haasea00f3862011-02-22 06:34:40 -0800912 NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
913 mPendingAnimations.add(nameValuePair);
Chet Haase3a000a52011-06-16 13:55:11 -0700914 mView.removeCallbacks(mAnimationStarter);
Chet Haasedcfbd6a2013-05-09 14:40:21 -0700915 mView.postOnAnimation(mAnimationStarter);
Chet Haasea00f3862011-02-22 06:34:40 -0800916 }
917
918 /**
919 * This method handles setting the property values directly in the View object's fields.
920 * propertyConstant tells it which property should be set, value is the value to set
921 * the property to.
922 *
923 * @param propertyConstant The property to be set
924 * @param value The value to set the property to
925 */
926 private void setValue(int propertyConstant, float value) {
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700927 final View.TransformationInfo info = mView.mTransformationInfo;
Chet Haase1271e2c2012-04-20 09:54:27 -0700928 final DisplayList displayList = mView.mDisplayList;
Chet Haasea00f3862011-02-22 06:34:40 -0800929 switch (propertyConstant) {
930 case TRANSLATION_X:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700931 info.mTranslationX = value;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700932 if (displayList != null) displayList.setTranslationX(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800933 break;
934 case TRANSLATION_Y:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700935 info.mTranslationY = value;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700936 if (displayList != null) displayList.setTranslationY(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800937 break;
Chris Craikf57776b2013-10-25 18:30:17 -0700938 case TRANSLATION_Z:
939 info.mTranslationZ = value;
940 if (displayList != null) displayList.setTranslationZ(value);
941 break;
Chet Haasea00f3862011-02-22 06:34:40 -0800942 case ROTATION:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700943 info.mRotation = value;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700944 if (displayList != null) displayList.setRotation(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800945 break;
946 case ROTATION_X:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700947 info.mRotationX = value;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700948 if (displayList != null) displayList.setRotationX(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800949 break;
950 case ROTATION_Y:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700951 info.mRotationY = value;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700952 if (displayList != null) displayList.setRotationY(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800953 break;
954 case SCALE_X:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700955 info.mScaleX = value;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700956 if (displayList != null) displayList.setScaleX(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800957 break;
958 case SCALE_Y:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700959 info.mScaleY = value;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700960 if (displayList != null) displayList.setScaleY(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800961 break;
962 case X:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700963 info.mTranslationX = value - mView.mLeft;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700964 if (displayList != null) displayList.setTranslationX(value - mView.mLeft);
Chet Haasea00f3862011-02-22 06:34:40 -0800965 break;
966 case Y:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700967 info.mTranslationY = value - mView.mTop;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700968 if (displayList != null) displayList.setTranslationY(value - mView.mTop);
Chet Haasea00f3862011-02-22 06:34:40 -0800969 break;
970 case ALPHA:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700971 info.mAlpha = value;
Chet Haasedb8c9a62012-03-21 18:54:18 -0700972 if (displayList != null) displayList.setAlpha(value);
Chet Haasea00f3862011-02-22 06:34:40 -0800973 break;
974 }
975 }
976
977 /**
978 * This method gets the value of the named property from the View object.
979 *
980 * @param propertyConstant The property whose value should be returned
981 * @return float The value of the named property
982 */
983 private float getValue(int propertyConstant) {
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700984 final View.TransformationInfo info = mView.mTransformationInfo;
Chet Haasea00f3862011-02-22 06:34:40 -0800985 switch (propertyConstant) {
986 case TRANSLATION_X:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700987 return info.mTranslationX;
Chet Haasea00f3862011-02-22 06:34:40 -0800988 case TRANSLATION_Y:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700989 return info.mTranslationY;
Chris Craikf57776b2013-10-25 18:30:17 -0700990 case TRANSLATION_Z:
991 return info.mTranslationZ;
Chet Haasea00f3862011-02-22 06:34:40 -0800992 case ROTATION:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700993 return info.mRotation;
Chet Haasea00f3862011-02-22 06:34:40 -0800994 case ROTATION_X:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700995 return info.mRotationX;
Chet Haasea00f3862011-02-22 06:34:40 -0800996 case ROTATION_Y:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700997 return info.mRotationY;
Chet Haasea00f3862011-02-22 06:34:40 -0800998 case SCALE_X:
Dianne Hackbornddb715b2011-09-09 14:43:39 -0700999 return info.mScaleX;
Chet Haasea00f3862011-02-22 06:34:40 -08001000 case SCALE_Y:
Dianne Hackbornddb715b2011-09-09 14:43:39 -07001001 return info.mScaleY;
Chet Haasea00f3862011-02-22 06:34:40 -08001002 case X:
Dianne Hackbornddb715b2011-09-09 14:43:39 -07001003 return mView.mLeft + info.mTranslationX;
Chet Haasea00f3862011-02-22 06:34:40 -08001004 case Y:
Dianne Hackbornddb715b2011-09-09 14:43:39 -07001005 return mView.mTop + info.mTranslationY;
Chet Haasea00f3862011-02-22 06:34:40 -08001006 case ALPHA:
Dianne Hackbornddb715b2011-09-09 14:43:39 -07001007 return info.mAlpha;
Chet Haasea00f3862011-02-22 06:34:40 -08001008 }
1009 return 0;
1010 }
1011
1012 /**
1013 * Utility class that handles the various Animator events. The only ones we care
1014 * about are the end event (which we use to clean up the animator map when an animator
1015 * finishes) and the update event (which we use to calculate the current value of each
1016 * property and then set it on the view object).
1017 */
1018 private class AnimatorEventListener
1019 implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
1020 @Override
1021 public void onAnimationStart(Animator animation) {
Chet Haasec1ca6652012-01-31 07:33:48 -08001022 if (mAnimatorSetupMap != null) {
1023 Runnable r = mAnimatorSetupMap.get(animation);
1024 if (r != null) {
1025 r.run();
1026 }
1027 mAnimatorSetupMap.remove(animation);
1028 }
1029 if (mAnimatorOnStartMap != null) {
1030 Runnable r = mAnimatorOnStartMap.get(animation);
1031 if (r != null) {
1032 r.run();
1033 }
1034 mAnimatorOnStartMap.remove(animation);
1035 }
Chet Haasea00f3862011-02-22 06:34:40 -08001036 if (mListener != null) {
1037 mListener.onAnimationStart(animation);
1038 }
1039 }
1040
1041 @Override
1042 public void onAnimationCancel(Animator animation) {
1043 if (mListener != null) {
1044 mListener.onAnimationCancel(animation);
1045 }
Chet Haasec1ca6652012-01-31 07:33:48 -08001046 if (mAnimatorOnEndMap != null) {
1047 mAnimatorOnEndMap.remove(animation);
1048 }
Chet Haasea00f3862011-02-22 06:34:40 -08001049 }
1050
1051 @Override
1052 public void onAnimationRepeat(Animator animation) {
1053 if (mListener != null) {
1054 mListener.onAnimationRepeat(animation);
1055 }
1056 }
1057
1058 @Override
1059 public void onAnimationEnd(Animator animation) {
Chet Haase563d4f22012-04-18 16:20:08 -07001060 mView.setHasTransientState(false);
Chet Haasea00f3862011-02-22 06:34:40 -08001061 if (mListener != null) {
1062 mListener.onAnimationEnd(animation);
1063 }
Chet Haasec1ca6652012-01-31 07:33:48 -08001064 if (mAnimatorOnEndMap != null) {
1065 Runnable r = mAnimatorOnEndMap.get(animation);
1066 if (r != null) {
1067 r.run();
1068 }
1069 mAnimatorOnEndMap.remove(animation);
1070 }
1071 if (mAnimatorCleanupMap != null) {
1072 Runnable r = mAnimatorCleanupMap.get(animation);
1073 if (r != null) {
1074 r.run();
1075 }
1076 mAnimatorCleanupMap.remove(animation);
1077 }
Chet Haasea00f3862011-02-22 06:34:40 -08001078 mAnimatorMap.remove(animation);
1079 }
1080
1081 /**
1082 * Calculate the current value for each property and set it on the view. Invalidate
1083 * the view object appropriately, depending on which properties are being animated.
1084 *
1085 * @param animation The animator associated with the properties that need to be
1086 * set. This animator holds the animation fraction which we will use to calculate
1087 * the current value of each property.
1088 */
1089 @Override
1090 public void onAnimationUpdate(ValueAnimator animation) {
Chet Haase0c6d83cc2011-12-01 08:38:13 -08001091 PropertyBundle propertyBundle = mAnimatorMap.get(animation);
1092 if (propertyBundle == null) {
1093 // Shouldn't happen, but just to play it safe
1094 return;
1095 }
Chet Haase1271e2c2012-04-20 09:54:27 -07001096 boolean useDisplayListProperties = mView.mDisplayList != null;
Chet Haase9d1992d2012-03-13 11:03:25 -07001097
Chet Haasea00f3862011-02-22 06:34:40 -08001098 // alpha requires slightly different treatment than the other (transform) properties.
1099 // The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
1100 // logic is dependent on how the view handles an internal call to onSetAlpha().
1101 // We track what kinds of properties are set, and how alpha is handled when it is
1102 // set, and perform the invalidation steps appropriately.
1103 boolean alphaHandled = false;
Chet Haase9d1992d2012-03-13 11:03:25 -07001104 if (!useDisplayListProperties) {
1105 mView.invalidateParentCaches();
1106 }
Chet Haasea00f3862011-02-22 06:34:40 -08001107 float fraction = animation.getAnimatedFraction();
Chet Haasea00f3862011-02-22 06:34:40 -08001108 int propertyMask = propertyBundle.mPropertyMask;
1109 if ((propertyMask & TRANSFORM_MASK) != 0) {
Chet Haase9d1992d2012-03-13 11:03:25 -07001110 mView.invalidateViewProperty(false, false);
Chet Haasea00f3862011-02-22 06:34:40 -08001111 }
1112 ArrayList<NameValuesHolder> valueList = propertyBundle.mNameValuesHolder;
1113 if (valueList != null) {
1114 int count = valueList.size();
1115 for (int i = 0; i < count; ++i) {
1116 NameValuesHolder values = valueList.get(i);
1117 float value = values.mFromValue + fraction * values.mDeltaValue;
1118 if (values.mNameConstant == ALPHA) {
1119 alphaHandled = mView.setAlphaNoInvalidation(value);
1120 } else {
1121 setValue(values.mNameConstant, value);
1122 }
1123 }
1124 }
1125 if ((propertyMask & TRANSFORM_MASK) != 0) {
Dianne Hackbornddb715b2011-09-09 14:43:39 -07001126 mView.mTransformationInfo.mMatrixDirty = true;
Chet Haase9d1992d2012-03-13 11:03:25 -07001127 if (!useDisplayListProperties) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001128 mView.mPrivateFlags |= View.PFLAG_DRAWN; // force another invalidation
Chet Haase9d1992d2012-03-13 11:03:25 -07001129 }
Chet Haasea00f3862011-02-22 06:34:40 -08001130 }
1131 // invalidate(false) in all cases except if alphaHandled gets set to true
1132 // via the call to setAlphaNoInvalidation(), above
Chet Haase9d1992d2012-03-13 11:03:25 -07001133 if (alphaHandled) {
1134 mView.invalidate(true);
1135 } else {
1136 mView.invalidateViewProperty(false, false);
1137 }
Chet Haase87f4ae62013-09-06 18:29:56 -07001138 if (mUpdateListener != null) {
1139 mUpdateListener.onAnimationUpdate(animation);
1140 }
Chet Haasea00f3862011-02-22 06:34:40 -08001141 }
1142 }
1143}