blob: 22dd3c7b8dafa599fc7b6476a94c73b4043c5046 [file] [log] [blame]
Chet Haase21cd1382010-09-01 17:42:29 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.animation;
18
19import android.view.View;
20import android.view.ViewGroup;
21import android.view.ViewTreeObserver;
22import android.view.animation.AccelerateDecelerateInterpolator;
23import android.view.animation.DecelerateInterpolator;
Chet Haase21cd1382010-09-01 17:42:29 -070024
25import java.util.ArrayList;
26import java.util.HashMap;
27import java.util.List;
28
29/**
30 * This class enables automatic animations on layout changes in ViewGroup objects. To enable
31 * transitions for a layout container, create a LayoutTransition object and set it on any
32 * ViewGroup by calling {@link ViewGroup#setLayoutTransition(LayoutTransition)}. This will cause
33 * default animations to run whenever items are added to or removed from that container. To specify
Chet Haasea18a86b2010-09-07 13:20:00 -070034 * custom animations, use the {@link LayoutTransition#setAnimator(int, Animator)
35 * setAnimator()} method.
Chet Haase21cd1382010-09-01 17:42:29 -070036 *
Chet Haasedaf98e92011-01-10 14:10:36 -080037 * <p>One of the core concepts of these transition animations is that there are two types of
Chet Haase21cd1382010-09-01 17:42:29 -070038 * changes that cause the transition and four different animations that run because of
39 * those changes. The changes that trigger the transition are items being added to a container
40 * (referred to as an "appearing" transition) or removed from a container (also known as
Chet Haasedaf98e92011-01-10 14:10:36 -080041 * "disappearing"). Setting the visibility of views (between GONE and VISIBLE) will trigger
42 * the same add/remove logic. The animations that run due to those events are one that animates
Chet Haase21cd1382010-09-01 17:42:29 -070043 * items being added, one that animates items being removed, and two that animate the other
44 * items in the container that change due to the add/remove occurrence. Users of
45 * the transition may want different animations for the changing items depending on whether
Chet Haasedaf98e92011-01-10 14:10:36 -080046 * they are changing due to an appearing or disappearing event, so there is one animation for
Chet Haase21cd1382010-09-01 17:42:29 -070047 * each of these variations of the changing event. Most of the API of this class is concerned
48 * with setting up the basic properties of the animations used in these four situations,
49 * or with setting up custom animations for any or all of the four.</p>
50 *
51 * <p>The animations specified for the transition, both the defaults and any custom animations
52 * set on the transition object, are templates only. That is, these animations exist to hold the
53 * basic animation properties, such as the duration, start delay, and properties being animated.
54 * But the actual target object, as well as the start and end values for those properties, are
55 * set automatically in the process of setting up the transition each time it runs. Each of the
56 * animations is cloned from the original copy and the clone is then populated with the dynamic
57 * values of the target being animated (such as one of the items in a layout container that is
58 * moving as a result of the layout event) as well as the values that are changing (such as the
59 * position and size of that object). The actual values that are pushed to each animation
60 * depends on what properties are specified for the animation. For example, the default
61 * CHANGE_APPEARING animation animates <code>left</code>, <code>top</code>, <code>right</code>,
62 * and <code>bottom</code>. Values for these properties are updated with the pre- and post-layout
63 * values when the transition begins. Custom animations will be similarly populated with
Chet Haasea18a86b2010-09-07 13:20:00 -070064 * the target and values being animated, assuming they use ObjectAnimator objects with
Chet Haase21cd1382010-09-01 17:42:29 -070065 * property names that are known on the target object.</p>
Chet Haasedaf98e92011-01-10 14:10:36 -080066 *
67 * <p>This class, and the associated XML flag for containers, animateLayoutChanges="true",
68 * provides a simple utility meant for automating changes in straightforward situations.
69 * Using LayoutTransition at multiple levels of a nested view hierarchy may not work due to the
70 * interrelationship of the various levels of layout. Also, a container that is being scrolled
71 * at the same time as items are being added or removed is probably not a good candidate for
72 * this utility, because the before/after locations calculated by LayoutTransition
73 * may not match the actual locations when the animations finish due to the container
74 * being scrolled as the animations are running. You can work around that
75 * particular issue by disabling the 'changing' animations by setting the CHANGE_APPEARING
76 * and CHANGE_DISAPPEARING animations to null, and setting the startDelay of the
77 * other animations appropriately.</p>
Chet Haase21cd1382010-09-01 17:42:29 -070078 */
79public class LayoutTransition {
80
81 /**
82 * A flag indicating the animation that runs on those items that are changing
83 * due to a new item appearing in the container.
84 */
85 public static final int CHANGE_APPEARING = 0;
86
87 /**
88 * A flag indicating the animation that runs on those items that are changing
Chet Haase9e90a992011-01-04 16:23:21 -080089 * due to an item disappearing from the container.
Chet Haase21cd1382010-09-01 17:42:29 -070090 */
91 public static final int CHANGE_DISAPPEARING = 1;
92
93 /**
Chet Haase9e90a992011-01-04 16:23:21 -080094 * A flag indicating the animation that runs on those items that are appearing
95 * in the container.
Chet Haase21cd1382010-09-01 17:42:29 -070096 */
97 public static final int APPEARING = 2;
98
99 /**
Chet Haase9e90a992011-01-04 16:23:21 -0800100 * A flag indicating the animation that runs on those items that are disappearing
101 * from the container.
Chet Haase21cd1382010-09-01 17:42:29 -0700102 */
103 public static final int DISAPPEARING = 3;
104
105 /**
106 * These variables hold the animations that are currently used to run the transition effects.
107 * These animations are set to defaults, but can be changed to custom animations by
Chet Haasea18a86b2010-09-07 13:20:00 -0700108 * calls to setAnimator().
Chet Haase21cd1382010-09-01 17:42:29 -0700109 */
Chet Haasea18a86b2010-09-07 13:20:00 -0700110 private Animator mDisappearingAnim = null;
111 private Animator mAppearingAnim = null;
112 private Animator mChangingAppearingAnim = null;
113 private Animator mChangingDisappearingAnim = null;
Chet Haase21cd1382010-09-01 17:42:29 -0700114
115 /**
116 * These are the default animations, defined in the constructor, that will be used
117 * unless the user specifies custom animations.
118 */
Chet Haasea18a86b2010-09-07 13:20:00 -0700119 private static ObjectAnimator defaultChangeIn;
120 private static ObjectAnimator defaultChangeOut;
121 private static ObjectAnimator defaultFadeIn;
122 private static ObjectAnimator defaultFadeOut;
Chet Haase21cd1382010-09-01 17:42:29 -0700123
124 /**
125 * The default duration used by all animations.
126 */
127 private static long DEFAULT_DURATION = 300;
128
129 /**
130 * The durations of the four different animations
131 */
132 private long mChangingAppearingDuration = DEFAULT_DURATION;
133 private long mChangingDisappearingDuration = DEFAULT_DURATION;
134 private long mAppearingDuration = DEFAULT_DURATION;
135 private long mDisappearingDuration = DEFAULT_DURATION;
136
137 /**
138 * The start delays of the four different animations. Note that the default behavior of
139 * the appearing item is the default duration, since it should wait for the items to move
140 * before fading it. Same for the changing animation when disappearing; it waits for the item
141 * to fade out before moving the other items.
142 */
143 private long mAppearingDelay = DEFAULT_DURATION;
144 private long mDisappearingDelay = 0;
145 private long mChangingAppearingDelay = 0;
146 private long mChangingDisappearingDelay = DEFAULT_DURATION;
147
148 /**
149 * The inter-animation delays used on the two changing animations
150 */
151 private long mChangingAppearingStagger = 0;
152 private long mChangingDisappearingStagger = 0;
153
154 /**
155 * The default interpolators used for the animations
156 */
Chet Haasee0ee2e92010-10-07 09:06:18 -0700157 private TimeInterpolator mAppearingInterpolator = new AccelerateDecelerateInterpolator();
158 private TimeInterpolator mDisappearingInterpolator = new AccelerateDecelerateInterpolator();
159 private TimeInterpolator mChangingAppearingInterpolator = new DecelerateInterpolator();
160 private TimeInterpolator mChangingDisappearingInterpolator = new DecelerateInterpolator();
Chet Haase21cd1382010-09-01 17:42:29 -0700161
162 /**
Chet Haasee64ea872010-12-13 16:15:53 -0800163 * These hashmaps are used to store the animations that are currently running as part of
Chet Haase21cd1382010-09-01 17:42:29 -0700164 * the transition. The reason for this is that a further layout event should cause
165 * existing animations to stop where they are prior to starting new animations. So
166 * we cache all of the current animations in this map for possible cancellation on
167 * another layout event.
168 */
Chet Haase0dfc3982011-01-28 14:13:22 -0800169 private final HashMap<View, Animator> pendingAnimations = new HashMap<View, Animator>();
Ben Komalocbda9102010-12-16 15:55:27 -0800170 private final HashMap<View, Animator> currentChangingAnimations = new HashMap<View, Animator>();
Chet Haasee8e45d32011-03-02 17:07:35 -0800171 private final HashMap<View, Animator> currentAppearingAnimations =
172 new HashMap<View, Animator>();
173 private final HashMap<View, Animator> currentDisappearingAnimations =
Ben Komalocbda9102010-12-16 15:55:27 -0800174 new HashMap<View, Animator>();
Chet Haase21cd1382010-09-01 17:42:29 -0700175
176 /**
177 * This hashmap is used to track the listeners that have been added to the children of
178 * a container. When a layout change occurs, an animation is created for each View, so that
179 * the pre-layout values can be cached in that animation. Then a listener is added to the
180 * view to see whether the layout changes the bounds of that view. If so, the animation
181 * is set with the final values and then run. If not, the animation is not started. When
182 * the process of setting up and running all appropriate animations is done, we need to
183 * remove these listeners and clear out the map.
184 */
Ben Komalocbda9102010-12-16 15:55:27 -0800185 private final HashMap<View, View.OnLayoutChangeListener> layoutChangeListenerMap =
Chet Haase21cd1382010-09-01 17:42:29 -0700186 new HashMap<View, View.OnLayoutChangeListener>();
187
188 /**
189 * Used to track the current delay being assigned to successive animations as they are
190 * started. This value is incremented for each new animation, then zeroed before the next
191 * transition begins.
192 */
193 private long staggerDelay;
194
195 /**
196 * The set of listeners that should be notified when APPEARING/DISAPPEARING transitions
197 * start and end.
198 */
199 private ArrayList<TransitionListener> mListeners;
200
201
202 /**
203 * Constructs a LayoutTransition object. By default, the object will listen to layout
204 * events on any ViewGroup that it is set on and will run default animations for each
205 * type of layout event.
206 */
207 public LayoutTransition() {
208 if (defaultChangeIn == null) {
209 // "left" is just a placeholder; we'll put real properties/values in when needed
Chet Haase2794eb32010-10-12 16:29:28 -0700210 PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left", 0, 1);
211 PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0, 1);
212 PropertyValuesHolder pvhRight = PropertyValuesHolder.ofInt("right", 0, 1);
213 PropertyValuesHolder pvhBottom = PropertyValuesHolder.ofInt("bottom", 0, 1);
214 defaultChangeIn = ObjectAnimator.ofPropertyValuesHolder(this,
Chet Haase21cd1382010-09-01 17:42:29 -0700215 pvhLeft, pvhTop, pvhRight, pvhBottom);
Chet Haase2794eb32010-10-12 16:29:28 -0700216 defaultChangeIn.setDuration(DEFAULT_DURATION);
Chet Haase21cd1382010-09-01 17:42:29 -0700217 defaultChangeIn.setStartDelay(mChangingAppearingDelay);
218 defaultChangeIn.setInterpolator(mChangingAppearingInterpolator);
219 defaultChangeOut = defaultChangeIn.clone();
220 defaultChangeOut.setStartDelay(mChangingDisappearingDelay);
221 defaultChangeOut.setInterpolator(mChangingDisappearingInterpolator);
Chet Haase2794eb32010-10-12 16:29:28 -0700222 defaultFadeIn = ObjectAnimator.ofFloat(this, "alpha", 0f, 1f);
223 defaultFadeIn.setDuration(DEFAULT_DURATION);
Chet Haase21cd1382010-09-01 17:42:29 -0700224 defaultFadeIn.setStartDelay(mAppearingDelay);
225 defaultFadeIn.setInterpolator(mAppearingInterpolator);
Chet Haase2794eb32010-10-12 16:29:28 -0700226 defaultFadeOut = ObjectAnimator.ofFloat(this, "alpha", 1f, 0f);
227 defaultFadeOut.setDuration(DEFAULT_DURATION);
Chet Haase21cd1382010-09-01 17:42:29 -0700228 defaultFadeOut.setStartDelay(mDisappearingDelay);
229 defaultFadeOut.setInterpolator(mDisappearingInterpolator);
230 }
231 mChangingAppearingAnim = defaultChangeIn;
232 mChangingDisappearingAnim = defaultChangeOut;
233 mAppearingAnim = defaultFadeIn;
234 mDisappearingAnim = defaultFadeOut;
235 }
236
237 /**
238 * Sets the duration to be used by all animations of this transition object. If you want to
239 * set the duration of just one of the animations in particular, use the
240 * {@link #setDuration(int, long)} method.
241 *
242 * @param duration The length of time, in milliseconds, that the transition animations
243 * should last.
244 */
245 public void setDuration(long duration) {
246 mChangingAppearingDuration = duration;
247 mChangingDisappearingDuration = duration;
248 mAppearingDuration = duration;
249 mDisappearingDuration = duration;
250 }
251
252 /**
253 * Sets the start delay on one of the animation objects used by this transition. The
254 * <code>transitionType</code> parameter determines the animation whose start delay
255 * is being set.
256 *
257 * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
258 * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose start
259 * delay is being set.
260 * @param delay The length of time, in milliseconds, to delay before starting the animation.
Chet Haasea18a86b2010-09-07 13:20:00 -0700261 * @see Animator#setStartDelay(long)
Chet Haase21cd1382010-09-01 17:42:29 -0700262 */
263 public void setStartDelay(int transitionType, long delay) {
264 switch (transitionType) {
265 case CHANGE_APPEARING:
266 mChangingAppearingDelay = delay;
267 break;
268 case CHANGE_DISAPPEARING:
269 mChangingDisappearingDelay = delay;
270 break;
271 case APPEARING:
272 mAppearingDelay = delay;
273 break;
274 case DISAPPEARING:
275 mDisappearingDelay = delay;
276 break;
277 }
278 }
279
280 /**
281 * Gets the start delay on one of the animation objects used by this transition. The
282 * <code>transitionType</code> parameter determines the animation whose start delay
283 * is returned.
284 *
285 * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
286 * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose start
287 * delay is returned.
288 * @return long The start delay of the specified animation.
Chet Haasea18a86b2010-09-07 13:20:00 -0700289 * @see Animator#getStartDelay()
Chet Haase21cd1382010-09-01 17:42:29 -0700290 */
291 public long getStartDelay(int transitionType) {
292 switch (transitionType) {
293 case CHANGE_APPEARING:
294 return mChangingAppearingDuration;
295 case CHANGE_DISAPPEARING:
296 return mChangingDisappearingDuration;
297 case APPEARING:
298 return mAppearingDuration;
299 case DISAPPEARING:
300 return mDisappearingDuration;
301 }
302 // shouldn't reach here
303 return 0;
304 }
305
306 /**
307 * Sets the duration on one of the animation objects used by this transition. The
308 * <code>transitionType</code> parameter determines the animation whose duration
309 * is being set.
310 *
311 * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
312 * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
313 * duration is being set.
314 * @param duration The length of time, in milliseconds, that the specified animation should run.
Chet Haasea18a86b2010-09-07 13:20:00 -0700315 * @see Animator#setDuration(long)
Chet Haase21cd1382010-09-01 17:42:29 -0700316 */
317 public void setDuration(int transitionType, long duration) {
318 switch (transitionType) {
319 case CHANGE_APPEARING:
320 mChangingAppearingDuration = duration;
321 break;
322 case CHANGE_DISAPPEARING:
323 mChangingDisappearingDuration = duration;
324 break;
325 case APPEARING:
326 mAppearingDuration = duration;
327 break;
328 case DISAPPEARING:
329 mDisappearingDuration = duration;
330 break;
331 }
332 }
333
334 /**
335 * Gets the duration on one of the animation objects used by this transition. The
336 * <code>transitionType</code> parameter determines the animation whose duration
337 * is returned.
338 *
339 * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
340 * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
341 * duration is returned.
342 * @return long The duration of the specified animation.
Chet Haasea18a86b2010-09-07 13:20:00 -0700343 * @see Animator#getDuration()
Chet Haase21cd1382010-09-01 17:42:29 -0700344 */
345 public long getDuration(int transitionType) {
346 switch (transitionType) {
347 case CHANGE_APPEARING:
348 return mChangingAppearingDuration;
349 case CHANGE_DISAPPEARING:
350 return mChangingDisappearingDuration;
351 case APPEARING:
352 return mAppearingDuration;
353 case DISAPPEARING:
354 return mDisappearingDuration;
355 }
356 // shouldn't reach here
357 return 0;
358 }
359
360 /**
361 * Sets the length of time to delay between starting each animation during one of the
362 * CHANGE animations.
363 *
364 * @param transitionType A value of {@link #CHANGE_APPEARING} or @link #CHANGE_DISAPPEARING}.
365 * @param duration The length of time, in milliseconds, to delay before launching the next
366 * animation in the sequence.
367 */
368 public void setStagger(int transitionType, long duration) {
369 switch (transitionType) {
370 case CHANGE_APPEARING:
371 mChangingAppearingStagger = duration;
372 break;
373 case CHANGE_DISAPPEARING:
374 mChangingDisappearingStagger = duration;
375 break;
376 // noop other cases
377 }
378 }
379
380 /**
381 * Tets the length of time to delay between starting each animation during one of the
382 * CHANGE animations.
383 *
384 * @param transitionType A value of {@link #CHANGE_APPEARING} or @link #CHANGE_DISAPPEARING}.
385 * @return long The length of time, in milliseconds, to delay before launching the next
386 * animation in the sequence.
387 */
388 public long getStagger(int transitionType) {
389 switch (transitionType) {
390 case CHANGE_APPEARING:
391 return mChangingAppearingStagger;
392 case CHANGE_DISAPPEARING:
393 return mChangingDisappearingStagger;
394 }
395 // shouldn't reach here
396 return 0;
397 }
398
399 /**
400 * Sets the interpolator on one of the animation objects used by this transition. The
401 * <code>transitionType</code> parameter determines the animation whose interpolator
402 * is being set.
403 *
404 * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
405 * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
406 * duration is being set.
407 * @param interpolator The interpolator that the specified animation should use.
Chet Haasee0ee2e92010-10-07 09:06:18 -0700408 * @see Animator#setInterpolator(TimeInterpolator)
Chet Haase21cd1382010-09-01 17:42:29 -0700409 */
Chet Haasee0ee2e92010-10-07 09:06:18 -0700410 public void setInterpolator(int transitionType, TimeInterpolator interpolator) {
Chet Haase21cd1382010-09-01 17:42:29 -0700411 switch (transitionType) {
412 case CHANGE_APPEARING:
413 mChangingAppearingInterpolator = interpolator;
414 break;
415 case CHANGE_DISAPPEARING:
416 mChangingDisappearingInterpolator = interpolator;
417 break;
418 case APPEARING:
419 mAppearingInterpolator = interpolator;
420 break;
421 case DISAPPEARING:
422 mDisappearingInterpolator = interpolator;
423 break;
424 }
425 }
426
427 /**
428 * Gets the interpolator on one of the animation objects used by this transition. The
429 * <code>transitionType</code> parameter determines the animation whose interpolator
430 * is returned.
431 *
432 * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
433 * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
434 * duration is being set.
Chet Haasee0ee2e92010-10-07 09:06:18 -0700435 * @return TimeInterpolator The interpolator that the specified animation uses.
436 * @see Animator#setInterpolator(TimeInterpolator)
Chet Haase21cd1382010-09-01 17:42:29 -0700437 */
Chet Haasee0ee2e92010-10-07 09:06:18 -0700438 public TimeInterpolator getInterpolator(int transitionType) {
Chet Haase21cd1382010-09-01 17:42:29 -0700439 switch (transitionType) {
440 case CHANGE_APPEARING:
441 return mChangingAppearingInterpolator;
442 case CHANGE_DISAPPEARING:
443 return mChangingDisappearingInterpolator;
444 case APPEARING:
445 return mAppearingInterpolator;
446 case DISAPPEARING:
447 return mDisappearingInterpolator;
448 }
449 // shouldn't reach here
450 return null;
451 }
452
453 /**
454 * Sets the animation used during one of the transition types that may run. Any
Chet Haasea18a86b2010-09-07 13:20:00 -0700455 * Animator object can be used, but to be most useful in the context of layout
456 * transitions, the animation should either be a ObjectAnimator or a AnimatorSet
457 * of animations including PropertyAnimators. Also, these ObjectAnimator objects
Chet Haase21cd1382010-09-01 17:42:29 -0700458 * should be able to get and set values on their target objects automatically. For
Chet Haasea18a86b2010-09-07 13:20:00 -0700459 * example, a ObjectAnimator that animates the property "left" is able to set and get the
Chet Haase21cd1382010-09-01 17:42:29 -0700460 * <code>left</code> property from the View objects being animated by the layout
461 * transition. The transition works by setting target objects and properties
462 * dynamically, according to the pre- and post-layoout values of those objects, so
463 * having animations that can handle those properties appropriately will work best
464 * for custom animation. The dynamic setting of values is only the case for the
465 * CHANGE animations; the APPEARING and DISAPPEARING animations are simply run with
466 * the values they have.
467 *
468 * <p>It is also worth noting that any and all animations (and their underlying
469 * PropertyValuesHolder objects) will have their start and end values set according
470 * to the pre- and post-layout values. So, for example, a custom animation on "alpha"
471 * as the CHANGE_APPEARING animation will inherit the real value of alpha on the target
472 * object (presumably 1) as its starting and ending value when the animation begins.
473 * Animations which need to use values at the beginning and end that may not match the
474 * values queried when the transition begins may need to use a different mechanism
Chet Haasea18a86b2010-09-07 13:20:00 -0700475 * than a standard ObjectAnimator object.</p>
Chet Haase21cd1382010-09-01 17:42:29 -0700476 *
477 * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
478 * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
479 * duration is being set.
Chet Haase5d6d7b92010-10-04 16:47:19 -0700480 * @param animator The animation being assigned. A value of <code>null</code> means that no
481 * animation will be run for the specified transitionType.
Chet Haase21cd1382010-09-01 17:42:29 -0700482 */
Chet Haasea18a86b2010-09-07 13:20:00 -0700483 public void setAnimator(int transitionType, Animator animator) {
Chet Haase21cd1382010-09-01 17:42:29 -0700484 switch (transitionType) {
485 case CHANGE_APPEARING:
Chet Haase5d6d7b92010-10-04 16:47:19 -0700486 mChangingAppearingAnim = animator;
Chet Haase21cd1382010-09-01 17:42:29 -0700487 break;
488 case CHANGE_DISAPPEARING:
Chet Haase5d6d7b92010-10-04 16:47:19 -0700489 mChangingDisappearingAnim = animator;
Chet Haase21cd1382010-09-01 17:42:29 -0700490 break;
491 case APPEARING:
Chet Haase5d6d7b92010-10-04 16:47:19 -0700492 mAppearingAnim = animator;
Chet Haase21cd1382010-09-01 17:42:29 -0700493 break;
494 case DISAPPEARING:
Chet Haase5d6d7b92010-10-04 16:47:19 -0700495 mDisappearingAnim = animator;
Chet Haase21cd1382010-09-01 17:42:29 -0700496 break;
497 }
498 }
499
500 /**
501 * Gets the animation used during one of the transition types that may run.
502 *
503 * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
504 * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
505 * duration is being set.
Chet Haasea18a86b2010-09-07 13:20:00 -0700506 * @return Animator The animation being used for the given transition type.
507 * @see #setAnimator(int, Animator)
Chet Haase21cd1382010-09-01 17:42:29 -0700508 */
Chet Haasea18a86b2010-09-07 13:20:00 -0700509 public Animator getAnimator(int transitionType) {
Chet Haase21cd1382010-09-01 17:42:29 -0700510 switch (transitionType) {
511 case CHANGE_APPEARING:
512 return mChangingAppearingAnim;
513 case CHANGE_DISAPPEARING:
514 return mChangingDisappearingAnim;
515 case APPEARING:
516 return mAppearingAnim;
517 case DISAPPEARING:
518 return mDisappearingAnim;
519 }
520 // shouldn't reach here
521 return null;
522 }
523
524 /**
525 * This function sets up runs animations on all of the views that change during layout.
526 * For every child in the parent, we create a change animation of the appropriate
527 * type (appearing or disappearing) and ask it to populate its start values from its
528 * target view. We add layout listeners to all child views and listen for changes. For
529 * those views that change, we populate the end values for those animations and start them.
530 * Animations are not run on unchanging views.
531 *
532 * @param parent The container which is undergoing an appearing or disappearing change.
533 * @param newView The view being added to or removed from the parent.
534 * @param changeReason A value of APPEARING or DISAPPEARING, indicating whether the
535 * transition is occuring because an item is being added to or removed from the parent.
536 */
537 private void runChangeTransition(final ViewGroup parent, View newView, final int changeReason) {
Chet Haase5d6d7b92010-10-04 16:47:19 -0700538
539 Animator baseAnimator = (changeReason == APPEARING) ?
540 mChangingAppearingAnim : mChangingDisappearingAnim;
541 // If the animation is null, there's nothing to do
542 if (baseAnimator == null) {
543 return;
544 }
545
Chet Haase21cd1382010-09-01 17:42:29 -0700546 // reset the inter-animation delay, in case we use it later
547 staggerDelay = 0;
Chet Haase0dfc3982011-01-28 14:13:22 -0800548 final long duration = (changeReason == APPEARING) ?
549 mChangingAppearingDuration : mChangingDisappearingDuration;
Chet Haase21cd1382010-09-01 17:42:29 -0700550
551 final ViewTreeObserver observer = parent.getViewTreeObserver(); // used for later cleanup
Chet Haase634a20a2010-09-08 16:36:57 -0700552 if (!observer.isAlive()) {
553 // If the observer's not in a good state, skip the transition
554 return;
555 }
Chet Haase21cd1382010-09-01 17:42:29 -0700556 int numChildren = parent.getChildCount();
557
558 for (int i = 0; i < numChildren; ++i) {
559 final View child = parent.getChildAt(i);
560
561 // only animate the views not being added or removed
562 if (child != newView) {
563
Chet Haase21cd1382010-09-01 17:42:29 -0700564
565 // Make a copy of the appropriate animation
Chet Haase5d6d7b92010-10-04 16:47:19 -0700566 final Animator anim = baseAnimator.clone();
Chet Haase21cd1382010-09-01 17:42:29 -0700567
568 // Set the target object for the animation
569 anim.setTarget(child);
570
Chet Haasea18a86b2010-09-07 13:20:00 -0700571 // A ObjectAnimator (or AnimatorSet of them) can extract start values from
Chet Haase21cd1382010-09-01 17:42:29 -0700572 // its target object
573 anim.setupStartValues();
574
Chet Haase0dfc3982011-01-28 14:13:22 -0800575 // If there's an animation running on this view already, cancel it
576 Animator currentAnimation = pendingAnimations.get(child);
577 if (currentAnimation != null) {
578 currentAnimation.cancel();
579 pendingAnimations.remove(child);
580 }
581 // Cache the animation in case we need to cancel it later
582 pendingAnimations.put(child, anim);
583
584 // For the animations which don't get started, we have to have a means of
585 // removing them from the cache, lest we leak them and their target objects.
586 // We run an animator for the default duration+100 (an arbitrary time, but one
587 // which should far surpass the delay between setting them up here and
588 // handling layout events which start them.
589 ValueAnimator pendingAnimRemover = ValueAnimator.ofFloat(0f, 1f).
590 setDuration(duration+100);
591 pendingAnimRemover.addListener(new AnimatorListenerAdapter() {
592 @Override
593 public void onAnimationEnd(Animator animation) {
594 pendingAnimations.remove(child);
595 }
596 });
597 pendingAnimRemover.start();
598
Chet Haase21cd1382010-09-01 17:42:29 -0700599 // Add a listener to track layout changes on this view. If we don't get a callback,
600 // then there's nothing to animate.
Chet Haase5e25c2c2010-09-16 11:15:56 -0700601 final View.OnLayoutChangeListener listener = new View.OnLayoutChangeListener() {
Chet Haase21cd1382010-09-01 17:42:29 -0700602 public void onLayoutChange(View v, int left, int top, int right, int bottom,
603 int oldLeft, int oldTop, int oldRight, int oldBottom) {
604
Chet Haase21cd1382010-09-01 17:42:29 -0700605 // Tell the animation to extract end values from the changed object
606 anim.setupEndValues();
607
608 long startDelay;
Chet Haase21cd1382010-09-01 17:42:29 -0700609 if (changeReason == APPEARING) {
610 startDelay = mChangingAppearingDelay + staggerDelay;
611 staggerDelay += mChangingAppearingStagger;
Chet Haase21cd1382010-09-01 17:42:29 -0700612 } else {
613 startDelay = mChangingDisappearingDelay + staggerDelay;
614 staggerDelay += mChangingDisappearingStagger;
Chet Haase21cd1382010-09-01 17:42:29 -0700615 }
616 anim.setStartDelay(startDelay);
617 anim.setDuration(duration);
618
Chet Haase0dfc3982011-01-28 14:13:22 -0800619 Animator prevAnimation = currentChangingAnimations.get(child);
620 if (prevAnimation != null) {
621 prevAnimation.cancel();
Chet Haase0dfc3982011-01-28 14:13:22 -0800622 }
623 Animator pendingAnimation = pendingAnimations.get(child);
624 if (pendingAnimation != null) {
625 pendingAnimations.remove(child);
626 }
Chet Haase9c087442011-01-12 16:20:16 -0800627 // Cache the animation in case we need to cancel it later
628 currentChangingAnimations.put(child, anim);
629
Chet Haasea18a86b2010-09-07 13:20:00 -0700630 if (anim instanceof ObjectAnimator) {
631 ((ObjectAnimator) anim).setCurrentPlayTime(0);
Chet Haase21cd1382010-09-01 17:42:29 -0700632 }
633 anim.start();
634
635 // this only removes listeners whose views changed - must clear the
636 // other listeners later
637 child.removeOnLayoutChangeListener(this);
638 layoutChangeListenerMap.remove(child);
639 }
640 };
Chet Haase5e25c2c2010-09-16 11:15:56 -0700641 // Remove the animation from the cache when it ends
642 anim.addListener(new AnimatorListenerAdapter() {
Chet Haase2954cd92011-01-09 09:43:39 -0800643
644 @Override
645 public void onAnimationStart(Animator animator) {
646 if (mListeners != null) {
647 for (TransitionListener listener : mListeners) {
648 listener.startTransition(LayoutTransition.this, parent, child,
649 changeReason == APPEARING ?
650 CHANGE_APPEARING : CHANGE_DISAPPEARING);
651 }
652 }
653 }
654
Ben Komalocbda9102010-12-16 15:55:27 -0800655 @Override
Chet Haase5e25c2c2010-09-16 11:15:56 -0700656 public void onAnimationCancel(Animator animator) {
Chet Haase5e25c2c2010-09-16 11:15:56 -0700657 child.removeOnLayoutChangeListener(listener);
658 layoutChangeListenerMap.remove(child);
659 }
Chet Haase2954cd92011-01-09 09:43:39 -0800660
Ben Komalocbda9102010-12-16 15:55:27 -0800661 @Override
Chet Haase5e25c2c2010-09-16 11:15:56 -0700662 public void onAnimationEnd(Animator animator) {
Chet Haaseadd65772011-02-09 16:47:29 -0800663 currentChangingAnimations.remove(child);
Chet Haase2954cd92011-01-09 09:43:39 -0800664 if (mListeners != null) {
665 for (TransitionListener listener : mListeners) {
666 listener.endTransition(LayoutTransition.this, parent, child,
667 changeReason == APPEARING ?
668 CHANGE_APPEARING : CHANGE_DISAPPEARING);
669 }
670 }
Chet Haase5e25c2c2010-09-16 11:15:56 -0700671 }
672 });
673
Chet Haase21cd1382010-09-01 17:42:29 -0700674 child.addOnLayoutChangeListener(listener);
675 // cache the listener for later removal
676 layoutChangeListenerMap.put(child, listener);
677 }
678 }
679 // This is the cleanup step. When we get this rendering event, we know that all of
680 // the appropriate animations have been set up and run. Now we can clear out the
681 // layout listeners.
682 observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
683 public boolean onPreDraw() {
Chet Haase634a20a2010-09-08 16:36:57 -0700684 parent.getViewTreeObserver().removeOnPreDrawListener(this);
Chet Haase21cd1382010-09-01 17:42:29 -0700685 int numChildren = parent.getChildCount();
686 for (int i = 0; i < numChildren; ++i) {
687 final View child = parent.getChildAt(i);
688 child.removeOnLayoutChangeListener(layoutChangeListenerMap.get(child));
689 }
690 layoutChangeListenerMap.clear();
691 return true;
692 }
693 });
694 }
695
696 /**
Chet Haase9c087442011-01-12 16:20:16 -0800697 * Returns true if animations are running which animate layout-related properties. This
698 * essentially means that either CHANGE_APPEARING or CHANGE_DISAPPEARING animations
699 * are running, since these animations operate on layout-related properties.
700 *
701 * @return true if CHANGE_APPEARING or CHANGE_DISAPPEARING animations are currently
702 * running.
703 */
704 public boolean isChangingLayout() {
705 return (currentChangingAnimations.size() > 0);
706 }
707
708 /**
709 * Returns true if any of the animations in this transition are currently running.
710 *
711 * @return true if any animations in the transition are running.
712 */
713 public boolean isRunning() {
Chet Haasee8e45d32011-03-02 17:07:35 -0800714 return (currentChangingAnimations.size() > 0 || currentAppearingAnimations.size() > 0 ||
715 currentDisappearingAnimations.size() > 0);
Chet Haase9c087442011-01-12 16:20:16 -0800716 }
717
718 /**
Chet Haaseadd65772011-02-09 16:47:29 -0800719 * Cancels the currently running transition. Note that we cancel() the changing animations
720 * but end() the visibility animations. This is because this method is currently called
721 * in the context of starting a new transition, so we want to move things from their mid-
722 * transition positions, but we want them to have their end-transition visibility.
723 *
724 * @hide
725 */
726 public void cancel() {
Chet Haasee8e45d32011-03-02 17:07:35 -0800727 if (currentChangingAnimations.size() > 0) {
728 HashMap<View, Animator> currentAnimCopy =
729 (HashMap<View, Animator>) currentChangingAnimations.clone();
730 for (Animator anim : currentAnimCopy.values()) {
731 anim.cancel();
732 }
733 currentChangingAnimations.clear();
Chet Haaseadd65772011-02-09 16:47:29 -0800734 }
Chet Haasee8e45d32011-03-02 17:07:35 -0800735 if (currentAppearingAnimations.size() > 0) {
736 HashMap<View, Animator> currentAnimCopy =
737 (HashMap<View, Animator>) currentAppearingAnimations.clone();
738 for (Animator anim : currentAnimCopy.values()) {
739 anim.end();
740 }
741 currentAppearingAnimations.clear();
Chet Haaseadd65772011-02-09 16:47:29 -0800742 }
Chet Haasee8e45d32011-03-02 17:07:35 -0800743 if (currentDisappearingAnimations.size() > 0) {
744 HashMap<View, Animator> currentAnimCopy =
745 (HashMap<View, Animator>) currentDisappearingAnimations.clone();
746 for (Animator anim : currentAnimCopy.values()) {
747 anim.end();
748 }
749 currentDisappearingAnimations.clear();
750 }
751 }
752
753 /**
754 * Cancels the specified type of transition. Note that we cancel() the changing animations
755 * but end() the visibility animations. This is because this method is currently called
756 * in the context of starting a new transition, so we want to move things from their mid-
757 * transition positions, but we want them to have their end-transition visibility.
758 *
759 * @hide
760 */
761 public void cancel(int transitionType) {
762 switch (transitionType) {
763 case CHANGE_APPEARING:
764 case CHANGE_DISAPPEARING:
765 if (currentChangingAnimations.size() > 0) {
766 HashMap<View, Animator> currentAnimCopy =
767 (HashMap<View, Animator>) currentChangingAnimations.clone();
768 for (Animator anim : currentAnimCopy.values()) {
769 anim.cancel();
770 }
771 currentChangingAnimations.clear();
772 }
773 break;
774 case APPEARING:
775 if (currentAppearingAnimations.size() > 0) {
776 HashMap<View, Animator> currentAnimCopy =
777 (HashMap<View, Animator>) currentAppearingAnimations.clone();
778 for (Animator anim : currentAnimCopy.values()) {
779 anim.end();
780 }
781 currentAppearingAnimations.clear();
782 }
783 break;
784 case DISAPPEARING:
785 if (currentDisappearingAnimations.size() > 0) {
786 HashMap<View, Animator> currentAnimCopy =
787 (HashMap<View, Animator>) currentDisappearingAnimations.clone();
788 for (Animator anim : currentAnimCopy.values()) {
789 anim.end();
790 }
791 currentDisappearingAnimations.clear();
792 }
793 break;
794 }
Chet Haaseadd65772011-02-09 16:47:29 -0800795 }
796
797 /**
Chet Haase21cd1382010-09-01 17:42:29 -0700798 * This method runs the animation that makes an added item appear.
799 *
800 * @param parent The ViewGroup to which the View is being added.
801 * @param child The View being added to the ViewGroup.
802 */
803 private void runAppearingTransition(final ViewGroup parent, final View child) {
Chet Haasee8e45d32011-03-02 17:07:35 -0800804 Animator currentAnimation = currentDisappearingAnimations.get(child);
Chet Haasee64ea872010-12-13 16:15:53 -0800805 if (currentAnimation != null) {
806 currentAnimation.cancel();
807 }
Chet Haase5d6d7b92010-10-04 16:47:19 -0700808 if (mAppearingAnim == null) {
809 if (mListeners != null) {
810 for (TransitionListener listener : mListeners) {
811 listener.endTransition(LayoutTransition.this, parent, child, APPEARING);
812 }
813 }
814 return;
815 }
Chet Haasea18a86b2010-09-07 13:20:00 -0700816 Animator anim = mAppearingAnim.clone();
Chet Haase21cd1382010-09-01 17:42:29 -0700817 anim.setTarget(child);
818 anim.setStartDelay(mAppearingDelay);
819 anim.setDuration(mAppearingDuration);
Chet Haasea18a86b2010-09-07 13:20:00 -0700820 if (anim instanceof ObjectAnimator) {
821 ((ObjectAnimator) anim).setCurrentPlayTime(0);
Chet Haase21cd1382010-09-01 17:42:29 -0700822 }
823 if (mListeners != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700824 anim.addListener(new AnimatorListenerAdapter() {
Ben Komalocbda9102010-12-16 15:55:27 -0800825 @Override
826 public void onAnimationEnd(Animator anim) {
Chet Haasee8e45d32011-03-02 17:07:35 -0800827 currentAppearingAnimations.remove(child);
Chet Haase21cd1382010-09-01 17:42:29 -0700828 for (TransitionListener listener : mListeners) {
829 listener.endTransition(LayoutTransition.this, parent, child, APPEARING);
830 }
831 }
832 });
833 }
Chet Haasee8e45d32011-03-02 17:07:35 -0800834 currentAppearingAnimations.put(child, anim);
Chet Haase21cd1382010-09-01 17:42:29 -0700835 anim.start();
836 }
837
838 /**
839 * This method runs the animation that makes a removed item disappear.
840 *
841 * @param parent The ViewGroup from which the View is being removed.
842 * @param child The View being removed from the ViewGroup.
843 */
844 private void runDisappearingTransition(final ViewGroup parent, final View child) {
Chet Haasee8e45d32011-03-02 17:07:35 -0800845 Animator currentAnimation = currentAppearingAnimations.get(child);
Chet Haasee64ea872010-12-13 16:15:53 -0800846 if (currentAnimation != null) {
847 currentAnimation.cancel();
848 }
Chet Haase5d6d7b92010-10-04 16:47:19 -0700849 if (mDisappearingAnim == null) {
850 if (mListeners != null) {
851 for (TransitionListener listener : mListeners) {
852 listener.endTransition(LayoutTransition.this, parent, child, DISAPPEARING);
853 }
854 }
855 return;
856 }
Chet Haasea18a86b2010-09-07 13:20:00 -0700857 Animator anim = mDisappearingAnim.clone();
Chet Haase21cd1382010-09-01 17:42:29 -0700858 anim.setStartDelay(mDisappearingDelay);
859 anim.setDuration(mDisappearingDuration);
860 anim.setTarget(child);
861 if (mListeners != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700862 anim.addListener(new AnimatorListenerAdapter() {
Chet Haase5e25c2c2010-09-16 11:15:56 -0700863 @Override
864 public void onAnimationEnd(Animator anim) {
Chet Haasee8e45d32011-03-02 17:07:35 -0800865 currentDisappearingAnimations.remove(child);
Chet Haase21cd1382010-09-01 17:42:29 -0700866 for (TransitionListener listener : mListeners) {
867 listener.endTransition(LayoutTransition.this, parent, child, DISAPPEARING);
868 }
869 }
870 });
871 }
Chet Haasea18a86b2010-09-07 13:20:00 -0700872 if (anim instanceof ObjectAnimator) {
873 ((ObjectAnimator) anim).setCurrentPlayTime(0);
Chet Haase21cd1382010-09-01 17:42:29 -0700874 }
Chet Haasee8e45d32011-03-02 17:07:35 -0800875 currentDisappearingAnimations.put(child, anim);
Chet Haase21cd1382010-09-01 17:42:29 -0700876 anim.start();
877 }
878
879 /**
880 * This method is called by ViewGroup when a child view is about to be added to the
881 * container. This callback starts the process of a transition; we grab the starting
882 * values, listen for changes to all of the children of the container, and start appropriate
883 * animations.
884 *
885 * @param parent The ViewGroup to which the View is being added.
886 * @param child The View being added to the ViewGroup.
887 */
Chet Haase5e25c2c2010-09-16 11:15:56 -0700888 public void addChild(ViewGroup parent, View child) {
Chet Haasee8e45d32011-03-02 17:07:35 -0800889 // Want disappearing animations to finish up before proceeding
890 cancel(DISAPPEARING);
891 // Also, cancel changing animations so that we start fresh ones from current locations
892 cancel(CHANGE_APPEARING);
Chet Haase21cd1382010-09-01 17:42:29 -0700893 if (mListeners != null) {
894 for (TransitionListener listener : mListeners) {
895 listener.startTransition(this, parent, child, APPEARING);
896 }
897 }
898 runChangeTransition(parent, child, APPEARING);
899 runAppearingTransition(parent, child);
900 }
901
902 /**
Chet Haase5e25c2c2010-09-16 11:15:56 -0700903 * This method is called by ViewGroup when a child view is about to be added to the
904 * container. This callback starts the process of a transition; we grab the starting
905 * values, listen for changes to all of the children of the container, and start appropriate
906 * animations.
907 *
908 * @param parent The ViewGroup to which the View is being added.
909 * @param child The View being added to the ViewGroup.
910 */
911 public void showChild(ViewGroup parent, View child) {
912 addChild(parent, child);
913 }
914
915 /**
Chet Haase21cd1382010-09-01 17:42:29 -0700916 * This method is called by ViewGroup when a child view is about to be removed from the
917 * container. This callback starts the process of a transition; we grab the starting
918 * values, listen for changes to all of the children of the container, and start appropriate
919 * animations.
920 *
921 * @param parent The ViewGroup from which the View is being removed.
922 * @param child The View being removed from the ViewGroup.
923 */
Chet Haase5e25c2c2010-09-16 11:15:56 -0700924 public void removeChild(ViewGroup parent, View child) {
Chet Haasee8e45d32011-03-02 17:07:35 -0800925 // Want appearing animations to finish up before proceeding
926 cancel(APPEARING);
927 // Also, cancel changing animations so that we start fresh ones from current locations
928 cancel(CHANGE_DISAPPEARING);
Chet Haase21cd1382010-09-01 17:42:29 -0700929 if (mListeners != null) {
930 for (TransitionListener listener : mListeners) {
931 listener.startTransition(this, parent, child, DISAPPEARING);
932 }
933 }
934 runChangeTransition(parent, child, DISAPPEARING);
935 runDisappearingTransition(parent, child);
936 }
937
938 /**
Chet Haase5e25c2c2010-09-16 11:15:56 -0700939 * This method is called by ViewGroup when a child view is about to be removed from the
940 * container. This callback starts the process of a transition; we grab the starting
941 * values, listen for changes to all of the children of the container, and start appropriate
942 * animations.
943 *
944 * @param parent The ViewGroup from which the View is being removed.
945 * @param child The View being removed from the ViewGroup.
946 */
947 public void hideChild(ViewGroup parent, View child) {
948 removeChild(parent, child);
949 }
950
951 /**
Chet Haase21cd1382010-09-01 17:42:29 -0700952 * Add a listener that will be called when the bounds of the view change due to
953 * layout processing.
954 *
955 * @param listener The listener that will be called when layout bounds change.
956 */
957 public void addTransitionListener(TransitionListener listener) {
958 if (mListeners == null) {
959 mListeners = new ArrayList<TransitionListener>();
960 }
961 mListeners.add(listener);
962 }
963
964 /**
965 * Remove a listener for layout changes.
966 *
967 * @param listener The listener for layout bounds change.
968 */
969 public void removeTransitionListener(TransitionListener listener) {
970 if (mListeners == null) {
971 return;
972 }
973 mListeners.remove(listener);
974 }
975
976 /**
977 * Gets the current list of listeners for layout changes.
978 * @return
979 */
980 public List<TransitionListener> getTransitionListeners() {
981 return mListeners;
982 }
983
984 /**
985 * This interface is used for listening to starting and ending events for transitions.
986 */
987 public interface TransitionListener {
988
989 /**
Chet Haase9c087442011-01-12 16:20:16 -0800990 * This event is sent to listeners when any type of transition animation begins.
Chet Haase21cd1382010-09-01 17:42:29 -0700991 *
992 * @param transition The LayoutTransition sending out the event.
993 * @param container The ViewGroup on which the transition is playing.
Chet Haase9c087442011-01-12 16:20:16 -0800994 * @param view The View object being affected by the transition animation.
995 * @param transitionType The type of transition that is beginning,
996 * {@link android.animation.LayoutTransition#APPEARING},
997 * {@link android.animation.LayoutTransition#DISAPPEARING},
998 * {@link android.animation.LayoutTransition#CHANGE_APPEARING}, or
999 * {@link android.animation.LayoutTransition#CHANGE_DISAPPEARING}.
Chet Haase21cd1382010-09-01 17:42:29 -07001000 */
1001 public void startTransition(LayoutTransition transition, ViewGroup container,
1002 View view, int transitionType);
1003
1004 /**
Chet Haase9c087442011-01-12 16:20:16 -08001005 * This event is sent to listeners when any type of transition animation ends.
Chet Haase21cd1382010-09-01 17:42:29 -07001006 *
1007 * @param transition The LayoutTransition sending out the event.
1008 * @param container The ViewGroup on which the transition is playing.
Chet Haase9c087442011-01-12 16:20:16 -08001009 * @param view The View object being affected by the transition animation.
1010 * @param transitionType The type of transition that is ending,
1011 * {@link android.animation.LayoutTransition#APPEARING},
1012 * {@link android.animation.LayoutTransition#DISAPPEARING},
1013 * {@link android.animation.LayoutTransition#CHANGE_APPEARING}, or
1014 * {@link android.animation.LayoutTransition#CHANGE_DISAPPEARING}.
Chet Haase21cd1382010-09-01 17:42:29 -07001015 */
1016 public void endTransition(LayoutTransition transition, ViewGroup container,
1017 View view, int transitionType);
1018 }
1019
1020}