blob: 313e33e601bdfe4c47f56923b6e88ac132c29b91 [file] [log] [blame]
Chet Haasefaebd8f2012-05-18 14:17:57 -07001/*
2 * Copyright (C) 2013 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 */
Chet Haase6ebe3de2013-06-17 16:50:50 -070016
Chet Haasefaebd8f2012-05-18 14:17:57 -070017package android.view.transition;
18
Chet Haasefaebd8f2012-05-18 14:17:57 -070019import android.util.AndroidRuntimeException;
Chet Haasefaebd8f2012-05-18 14:17:57 -070020import android.view.ViewGroup;
21
22import java.util.ArrayList;
Chet Haasefaebd8f2012-05-18 14:17:57 -070023
24/**
25 * A TransitionGroup is a parent of child transitions (including other
26 * TransitionGroups). Using TransitionGroups enables more complex
27 * choreography of transitions, where some groups play {@link #TOGETHER} and
28 * others play {@link #SEQUENTIALLY}. For example, {@link AutoTransition}
29 * uses a TransitionGroup to sequentially play a Fade(Fade.OUT), followed by
30 * a {@link Move}, followed by a Fade(Fade.OUT) transition.
31 */
32public class TransitionGroup extends Transition {
33
34 ArrayList<Transition> mTransitions = new ArrayList<Transition>();
35 private boolean mPlayTogether = true;
36 int mCurrentListeners;
37 boolean mStarted = false;
38
39 /**
40 * A flag used to indicate that the child transitions of this group
41 * should all start at the same time.
42 */
43 public static final int TOGETHER = 0;
44 /**
45 * A flag used to indicate that the child transitions of this group should
46 * play in sequence; when one child transition ends, the next child
47 * transition begins. Note that a transition does not end until all
48 * instances of it (which are playing on all applicable targets of the
49 * transition) end.
50 */
51 public static final int SEQUENTIALLY = 1;
52
53 /**
54 * Constructs an empty transition group. Add child transitions to the
55 * group by calling to {@link #addTransitions(Transition...)} )}. By default,
56 * child transitions will play {@link #TOGETHER}.
57 */
58 public TransitionGroup() {
59 }
60
61 /**
62 * Constructs an empty transition group with the specified ordering.
63 *
64 * @param ordering {@link #TOGETHER} to start this group's child
65 * transitions together, {@link #SEQUENTIALLY} to play the child
66 * transitions in sequence.
67 * @see #setOrdering(int)
68 */
69 public TransitionGroup(int ordering) {
70 setOrdering(ordering);
71 }
72
73 /**
74 * Sets the play order of this group's child transitions.
75 *
76 * @param ordering {@link #TOGETHER} to start this group's child
77 * transitions together, {@link #SEQUENTIALLY} to play the child
78 * transitions in sequence.
79 */
80 public void setOrdering(int ordering) {
81 switch (ordering) {
82 case SEQUENTIALLY:
83 mPlayTogether = false;
84 break;
85 case TOGETHER:
86 mPlayTogether = true;
87 break;
88 default:
89 throw new AndroidRuntimeException("Invalid parameter for TransitionGroup " +
90 "ordering: " + ordering);
91 }
92 }
93
94 /**
95 * Adds child transitions to this group. The order of the child transitions
96 * passed in determines the order in which they are started.
97 *
98 * @param transitions A list of child transition to be added to this group.
99 */
100 public void addTransitions(Transition... transitions) {
101 if (transitions != null) {
102 int numTransitions = transitions.length;
103 for (int i = 0; i < numTransitions; ++i) {
104 mTransitions.add(transitions[i]);
Chet Haase6ebe3de2013-06-17 16:50:50 -0700105 transitions[i].mParent = this;
Chet Haase867a8662013-06-03 07:30:21 -0700106 if (mDuration >= 0) {
Chet Haasedc57d9d2013-07-10 11:27:54 -0700107 transitions[i].setDuration(mDuration);
Chet Haase867a8662013-06-03 07:30:21 -0700108 }
Chet Haasefaebd8f2012-05-18 14:17:57 -0700109 }
110 }
111 }
112
113 /**
Chet Haase867a8662013-06-03 07:30:21 -0700114 * Setting a non-negative duration on a TransitionGroup causes all of the child
115 * transitions (current and future) to inherit this duration.
116 *
117 * @param duration The length of the animation, in milliseconds.
118 * @return This transitionGroup object.
119 */
120 @Override
121 public Transition setDuration(long duration) {
122 super.setDuration(duration);
123 if (mDuration >= 0) {
124 int numTransitions = mTransitions.size();
125 for (int i = 0; i < numTransitions; ++i) {
126 mTransitions.get(i).setDuration(duration);
127 }
128 }
129 return this;
130 }
131
132 /**
Chet Haasefaebd8f2012-05-18 14:17:57 -0700133 * Removes the specified child transition from this group.
134 *
135 * @param transition The transition to be removed.
136 */
137 public void removeTransition(Transition transition) {
138 mTransitions.remove(transition);
Chet Haase6ebe3de2013-06-17 16:50:50 -0700139 transition.mParent = null;
Chet Haasefaebd8f2012-05-18 14:17:57 -0700140 }
141
142 /**
143 * Sets up listeners for each of the child transitions. This is used to
144 * determine when this transition group is finished (all child transitions
145 * must finish first).
146 */
147 private void setupStartEndListeners() {
Chet Haase6ebe3de2013-06-17 16:50:50 -0700148 TransitionGroupListener listener = new TransitionGroupListener(this);
Chet Haasefaebd8f2012-05-18 14:17:57 -0700149 for (Transition childTransition : mTransitions) {
Chet Haase6ebe3de2013-06-17 16:50:50 -0700150 childTransition.addListener(listener);
Chet Haasefaebd8f2012-05-18 14:17:57 -0700151 }
152 mCurrentListeners = mTransitions.size();
153 }
154
155 /**
156 * This listener is used to detect when all child transitions are done, at
157 * which point this transition group is also done.
158 */
Chet Haase6ebe3de2013-06-17 16:50:50 -0700159 static class TransitionGroupListener extends TransitionListenerAdapter {
160 TransitionGroup mTransitionGroup;
161 TransitionGroupListener(TransitionGroup transitionGroup) {
162 mTransitionGroup = transitionGroup;
163 }
Chet Haasefaebd8f2012-05-18 14:17:57 -0700164 @Override
165 public void onTransitionStart(Transition transition) {
Chet Haase6ebe3de2013-06-17 16:50:50 -0700166 if (!mTransitionGroup.mStarted) {
167 mTransitionGroup.startTransition();
168 mTransitionGroup.mStarted = true;
Chet Haasefaebd8f2012-05-18 14:17:57 -0700169 }
170 }
171
172 @Override
173 public void onTransitionEnd(Transition transition) {
Chet Haase6ebe3de2013-06-17 16:50:50 -0700174 --mTransitionGroup.mCurrentListeners;
175 if (mTransitionGroup.mCurrentListeners == 0) {
Chet Haasefaebd8f2012-05-18 14:17:57 -0700176 // All child trans
Chet Haase6ebe3de2013-06-17 16:50:50 -0700177 mTransitionGroup.mStarted = false;
178 mTransitionGroup.endTransition();
Chet Haasefaebd8f2012-05-18 14:17:57 -0700179 }
180 transition.removeListener(this);
181 }
Chet Haasefaebd8f2012-05-18 14:17:57 -0700182 }
183
184 /**
185 * @hide
186 */
187 @Override
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700188 protected void play(ViewGroup sceneRoot, TransitionValuesMaps startValues,
Chet Haase6ebe3de2013-06-17 16:50:50 -0700189 TransitionValuesMaps endValues) {
190 for (Transition childTransition : mTransitions) {
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700191 childTransition.play(sceneRoot, startValues, endValues);
Chet Haase6ebe3de2013-06-17 16:50:50 -0700192 }
193 }
194
195 /**
196 * @hide
197 */
198 @Override
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700199 protected void runAnimations() {
Chet Haasefaebd8f2012-05-18 14:17:57 -0700200 setupStartEndListeners();
Chet Haasefaebd8f2012-05-18 14:17:57 -0700201 if (!mPlayTogether) {
202 // Setup sequence with listeners
203 // TODO: Need to add listeners in such a way that we can remove them later if canceled
204 for (int i = 1; i < mTransitions.size(); ++i) {
205 Transition previousTransition = mTransitions.get(i - 1);
206 final Transition nextTransition = mTransitions.get(i);
207 previousTransition.addListener(new TransitionListenerAdapter() {
208 @Override
209 public void onTransitionEnd(Transition transition) {
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700210 nextTransition.runAnimations();
Chet Haasefaebd8f2012-05-18 14:17:57 -0700211 transition.removeListener(this);
212 }
213 });
214 }
215 Transition firstTransition = mTransitions.get(0);
216 if (firstTransition != null) {
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700217 firstTransition.runAnimations();
Chet Haasefaebd8f2012-05-18 14:17:57 -0700218 }
219 } else {
220 for (Transition childTransition : mTransitions) {
Chet Haase2ea7f8b2013-06-21 15:00:05 -0700221 childTransition.runAnimations();
Chet Haasefaebd8f2012-05-18 14:17:57 -0700222 }
223 }
224 }
225
226 @Override
Chet Haasefaebd8f2012-05-18 14:17:57 -0700227 protected void captureValues(TransitionValues transitionValues, boolean start) {
228 int targetId = transitionValues.view.getId();
229 for (Transition childTransition : mTransitions) {
230 if (childTransition.isValidTarget(transitionValues.view, targetId)) {
231 childTransition.captureValues(transitionValues, start);
232 }
233 }
234 }
235
236 @Override
Chet Haasee9d32ea2013-06-04 08:46:42 -0700237 protected void cancelTransition() {
238 super.cancelTransition();
239 int numTransitions = mTransitions.size();
240 for (int i = 0; i < numTransitions; ++i) {
241 mTransitions.get(i).cancelTransition();
242 }
243 }
244
245 @Override
Chet Haase6ebe3de2013-06-17 16:50:50 -0700246 void setSceneRoot(ViewGroup sceneRoot) {
247 super.setSceneRoot(sceneRoot);
248 int numTransitions = mTransitions.size();
249 for (int i = 0; i < numTransitions; ++i) {
250 mTransitions.get(i).setSceneRoot(sceneRoot);
251 }
252 }
253
254 @Override
Chet Haasefaebd8f2012-05-18 14:17:57 -0700255 String toString(String indent) {
256 String result = super.toString(indent);
257 for (int i = 0; i < mTransitions.size(); ++i) {
258 result += "\n" + mTransitions.get(i).toString(indent + " ");
259 }
260 return result;
261 }
262
Chet Haase6ebe3de2013-06-17 16:50:50 -0700263 @Override
264 public TransitionGroup clone() {
265 TransitionGroup clone = (TransitionGroup) super.clone();
266 clone.mTransitions = new ArrayList<Transition>();
267 int numTransitions = mTransitions.size();
268 for (int i = 0; i < numTransitions; ++i) {
269 clone.mTransitions.add((Transition) mTransitions.get(i).clone());
270 }
271 return clone;
272 }
273
Chet Haasefaebd8f2012-05-18 14:17:57 -0700274}