| /* |
| * Copyright (C) 2013 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.view.transition; |
| |
| import android.util.AndroidRuntimeException; |
| import android.view.ViewGroup; |
| |
| import java.util.ArrayList; |
| |
| /** |
| * A TransitionGroup is a parent of child transitions (including other |
| * TransitionGroups). Using TransitionGroups enables more complex |
| * choreography of transitions, where some groups play {@link #TOGETHER} and |
| * others play {@link #SEQUENTIALLY}. For example, {@link AutoTransition} |
| * uses a TransitionGroup to sequentially play a Fade(Fade.OUT), followed by |
| * a {@link Move}, followed by a Fade(Fade.OUT) transition. |
| */ |
| public class TransitionGroup extends Transition { |
| |
| ArrayList<Transition> mTransitions = new ArrayList<Transition>(); |
| private boolean mPlayTogether = true; |
| int mCurrentListeners; |
| boolean mStarted = false; |
| |
| /** |
| * A flag used to indicate that the child transitions of this group |
| * should all start at the same time. |
| */ |
| public static final int TOGETHER = 0; |
| /** |
| * A flag used to indicate that the child transitions of this group should |
| * play in sequence; when one child transition ends, the next child |
| * transition begins. Note that a transition does not end until all |
| * instances of it (which are playing on all applicable targets of the |
| * transition) end. |
| */ |
| public static final int SEQUENTIALLY = 1; |
| |
| /** |
| * Constructs an empty transition group. Add child transitions to the |
| * group by calling to {@link #addTransitions(Transition...)} )}. By default, |
| * child transitions will play {@link #TOGETHER}. |
| */ |
| public TransitionGroup() { |
| } |
| |
| /** |
| * Constructs an empty transition group with the specified ordering. |
| * |
| * @param ordering {@link #TOGETHER} to start this group's child |
| * transitions together, {@link #SEQUENTIALLY} to play the child |
| * transitions in sequence. |
| * @see #setOrdering(int) |
| */ |
| public TransitionGroup(int ordering) { |
| setOrdering(ordering); |
| } |
| |
| /** |
| * Sets the play order of this group's child transitions. |
| * |
| * @param ordering {@link #TOGETHER} to start this group's child |
| * transitions together, {@link #SEQUENTIALLY} to play the child |
| * transitions in sequence. |
| */ |
| public void setOrdering(int ordering) { |
| switch (ordering) { |
| case SEQUENTIALLY: |
| mPlayTogether = false; |
| break; |
| case TOGETHER: |
| mPlayTogether = true; |
| break; |
| default: |
| throw new AndroidRuntimeException("Invalid parameter for TransitionGroup " + |
| "ordering: " + ordering); |
| } |
| } |
| |
| /** |
| * Adds child transitions to this group. The order of the child transitions |
| * passed in determines the order in which they are started. |
| * |
| * @param transitions A list of child transition to be added to this group. |
| */ |
| public void addTransitions(Transition... transitions) { |
| if (transitions != null) { |
| int numTransitions = transitions.length; |
| for (int i = 0; i < numTransitions; ++i) { |
| mTransitions.add(transitions[i]); |
| transitions[i].mParent = this; |
| if (mDuration >= 0) { |
| transitions[i].setDuration(mDuration); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Setting a non-negative duration on a TransitionGroup causes all of the child |
| * transitions (current and future) to inherit this duration. |
| * |
| * @param duration The length of the animation, in milliseconds. |
| * @return This transitionGroup object. |
| */ |
| @Override |
| public Transition setDuration(long duration) { |
| super.setDuration(duration); |
| if (mDuration >= 0) { |
| int numTransitions = mTransitions.size(); |
| for (int i = 0; i < numTransitions; ++i) { |
| mTransitions.get(i).setDuration(duration); |
| } |
| } |
| return this; |
| } |
| |
| /** |
| * Removes the specified child transition from this group. |
| * |
| * @param transition The transition to be removed. |
| */ |
| public void removeTransition(Transition transition) { |
| mTransitions.remove(transition); |
| transition.mParent = null; |
| } |
| |
| /** |
| * Sets up listeners for each of the child transitions. This is used to |
| * determine when this transition group is finished (all child transitions |
| * must finish first). |
| */ |
| private void setupStartEndListeners() { |
| TransitionGroupListener listener = new TransitionGroupListener(this); |
| for (Transition childTransition : mTransitions) { |
| childTransition.addListener(listener); |
| } |
| mCurrentListeners = mTransitions.size(); |
| } |
| |
| /** |
| * This listener is used to detect when all child transitions are done, at |
| * which point this transition group is also done. |
| */ |
| static class TransitionGroupListener extends TransitionListenerAdapter { |
| TransitionGroup mTransitionGroup; |
| TransitionGroupListener(TransitionGroup transitionGroup) { |
| mTransitionGroup = transitionGroup; |
| } |
| @Override |
| public void onTransitionStart(Transition transition) { |
| if (!mTransitionGroup.mStarted) { |
| mTransitionGroup.startTransition(); |
| mTransitionGroup.mStarted = true; |
| } |
| } |
| |
| @Override |
| public void onTransitionEnd(Transition transition) { |
| --mTransitionGroup.mCurrentListeners; |
| if (mTransitionGroup.mCurrentListeners == 0) { |
| // All child trans |
| mTransitionGroup.mStarted = false; |
| mTransitionGroup.endTransition(); |
| } |
| transition.removeListener(this); |
| } |
| } |
| |
| /** |
| * @hide |
| */ |
| @Override |
| protected void play(ViewGroup sceneRoot, TransitionValuesMaps startValues, |
| TransitionValuesMaps endValues) { |
| for (Transition childTransition : mTransitions) { |
| childTransition.play(sceneRoot, startValues, endValues); |
| } |
| } |
| |
| /** |
| * @hide |
| */ |
| @Override |
| protected void runAnimations() { |
| setupStartEndListeners(); |
| if (!mPlayTogether) { |
| // Setup sequence with listeners |
| // TODO: Need to add listeners in such a way that we can remove them later if canceled |
| for (int i = 1; i < mTransitions.size(); ++i) { |
| Transition previousTransition = mTransitions.get(i - 1); |
| final Transition nextTransition = mTransitions.get(i); |
| previousTransition.addListener(new TransitionListenerAdapter() { |
| @Override |
| public void onTransitionEnd(Transition transition) { |
| nextTransition.runAnimations(); |
| transition.removeListener(this); |
| } |
| }); |
| } |
| Transition firstTransition = mTransitions.get(0); |
| if (firstTransition != null) { |
| firstTransition.runAnimations(); |
| } |
| } else { |
| for (Transition childTransition : mTransitions) { |
| childTransition.runAnimations(); |
| } |
| } |
| } |
| |
| @Override |
| protected void captureValues(TransitionValues transitionValues, boolean start) { |
| int targetId = transitionValues.view.getId(); |
| for (Transition childTransition : mTransitions) { |
| if (childTransition.isValidTarget(transitionValues.view, targetId)) { |
| childTransition.captureValues(transitionValues, start); |
| } |
| } |
| } |
| |
| @Override |
| protected void cancelTransition() { |
| super.cancelTransition(); |
| int numTransitions = mTransitions.size(); |
| for (int i = 0; i < numTransitions; ++i) { |
| mTransitions.get(i).cancelTransition(); |
| } |
| } |
| |
| @Override |
| void setSceneRoot(ViewGroup sceneRoot) { |
| super.setSceneRoot(sceneRoot); |
| int numTransitions = mTransitions.size(); |
| for (int i = 0; i < numTransitions; ++i) { |
| mTransitions.get(i).setSceneRoot(sceneRoot); |
| } |
| } |
| |
| @Override |
| String toString(String indent) { |
| String result = super.toString(indent); |
| for (int i = 0; i < mTransitions.size(); ++i) { |
| result += "\n" + mTransitions.get(i).toString(indent + " "); |
| } |
| return result; |
| } |
| |
| @Override |
| public TransitionGroup clone() { |
| TransitionGroup clone = (TransitionGroup) super.clone(); |
| clone.mTransitions = new ArrayList<Transition>(); |
| int numTransitions = mTransitions.size(); |
| for (int i = 0; i < numTransitions; ++i) { |
| clone.mTransitions.add((Transition) mTransitions.get(i).clone()); |
| } |
| return clone; |
| } |
| |
| } |