/* * 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.transition; import android.animation.TimeInterpolator; import android.util.AndroidRuntimeException; import android.view.View; import android.view.ViewGroup; import java.util.ArrayList; /** * A TransitionSet is a parent of child transitions (including other * TransitionSets). Using TransitionSets enables more complex * choreography of transitions, where some sets play {@link #ORDERING_TOGETHER} and * others play {@link #ORDERING_SEQUENTIAL}. For example, {@link AutoTransition} * uses a TransitionSet to sequentially play a Fade(Fade.OUT), followed by * a {@link ChangeBounds}, followed by a Fade(Fade.OUT) transition. * *
A TransitionSet can be described in a resource file by using the
* tag transitionSet
, along with the standard
* attributes of {@link android.R.styleable#TransitionSet} and
* {@link android.R.styleable#Transition}. Child transitions of the
* TransitionSet object can be loaded by adding those child tags inside the
* enclosing transitionSet
tag. For example, the following xml
* describes a TransitionSet that plays a Fade and then a ChangeBounds
* transition on the affected view targets:
* <transitionSet xmlns:android="http://schemas.android.com/apk/res/android" * android:ordering="sequential"> * <fade/> * <changeBounds/> * </transitionSet> **/ public class TransitionSet extends Transition { ArrayList
If this transitionSet has a {@link #getDuration() duration} set on it, the * child transition will inherit that duration. Transitions are assumed to have * a maximum of one transitionSet parent.
* * @param transition A non-null child transition to be added to this set. * @return This transitionSet object. */ public TransitionSet addTransition(Transition transition) { if (transition != null) { mTransitions.add(transition); transition.mParent = this; if (mDuration >= 0) { transition.setDuration(mDuration); } } return this; } /** * Setting a non-negative duration on a TransitionSet causes all of the child * transitions (current and future) to inherit this duration. * * @param duration The length of the animation, in milliseconds. * @return This transitionSet object. */ @Override public TransitionSet 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; } @Override public TransitionSet setStartDelay(long startDelay) { return (TransitionSet) super.setStartDelay(startDelay); } @Override public TransitionSet setInterpolator(TimeInterpolator interpolator) { return (TransitionSet) super.setInterpolator(interpolator); } @Override public TransitionSet addTarget(View target) { return (TransitionSet) super.addTarget(target); } @Override public TransitionSet addTarget(int targetId) { return (TransitionSet) super.addTarget(targetId); } @Override public TransitionSet addListener(TransitionListener listener) { return (TransitionSet) super.addListener(listener); } @Override public TransitionSet removeTarget(int targetId) { return (TransitionSet) super.removeTarget(targetId); } @Override public TransitionSet removeTarget(View target) { return (TransitionSet) super.removeTarget(target); } @Override public TransitionSet removeListener(TransitionListener listener) { return (TransitionSet) super.removeListener(listener); } /** * Removes the specified child transition from this set. * * @param transition The transition to be removed. * @return This transitionSet object. */ public TransitionSet removeTransition(Transition transition) { mTransitions.remove(transition); transition.mParent = null; return this; } /** * Sets up listeners for each of the child transitions. This is used to * determine when this transition set is finished (all child transitions * must finish first). */ private void setupStartEndListeners() { TransitionSetListener listener = new TransitionSetListener(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 set is also done. */ static class TransitionSetListener extends TransitionListenerAdapter { TransitionSet mTransitionSet; TransitionSetListener(TransitionSet transitionSet) { mTransitionSet = transitionSet; } @Override public void onTransitionStart(Transition transition) { if (!mTransitionSet.mStarted) { mTransitionSet.start(); mTransitionSet.mStarted = true; } } @Override public void onTransitionEnd(Transition transition) { --mTransitionSet.mCurrentListeners; if (mTransitionSet.mCurrentListeners == 0) { // All child trans mTransitionSet.mStarted = false; mTransitionSet.end(); } transition.removeListener(this); } } /** * @hide */ @Override protected void createAnimators(ViewGroup sceneRoot, TransitionValuesMaps startValues, TransitionValuesMaps endValues) { for (Transition childTransition : mTransitions) { childTransition.createAnimators(sceneRoot, startValues, endValues); } } /** * @hide */ @Override protected void runAnimators() { 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.runAnimators(); transition.removeListener(this); } }); } Transition firstTransition = mTransitions.get(0); if (firstTransition != null) { firstTransition.runAnimators(); } } else { for (Transition childTransition : mTransitions) { childTransition.runAnimators(); } } } @Override public void captureStartValues(TransitionValues transitionValues) { int targetId = transitionValues.view.getId(); if (isValidTarget(transitionValues.view, targetId)) { for (Transition childTransition : mTransitions) { if (childTransition.isValidTarget(transitionValues.view, targetId)) { childTransition.captureStartValues(transitionValues); } } } } @Override public void captureEndValues(TransitionValues transitionValues) { int targetId = transitionValues.view.getId(); if (isValidTarget(transitionValues.view, targetId)) { for (Transition childTransition : mTransitions) { if (childTransition.isValidTarget(transitionValues.view, targetId)) { childTransition.captureEndValues(transitionValues); } } } } /** @hide */ @Override public void pause() { super.pause(); int numTransitions = mTransitions.size(); for (int i = 0; i < numTransitions; ++i) { mTransitions.get(i).pause(); } } /** @hide */ @Override public void resume() { super.resume(); int numTransitions = mTransitions.size(); for (int i = 0; i < numTransitions; ++i) { mTransitions.get(i).resume(); } } /** @hide */ @Override protected void cancel() { super.cancel(); int numTransitions = mTransitions.size(); for (int i = 0; i < numTransitions; ++i) { mTransitions.get(i).cancel(); } } @Override TransitionSet setSceneRoot(ViewGroup sceneRoot) { super.setSceneRoot(sceneRoot); int numTransitions = mTransitions.size(); for (int i = 0; i < numTransitions; ++i) { mTransitions.get(i).setSceneRoot(sceneRoot); } return (TransitionSet) this; } @Override void setCanRemoveViews(boolean canRemoveViews) { super.setCanRemoveViews(canRemoveViews); int numTransitions = mTransitions.size(); for (int i = 0; i < numTransitions; ++i) { mTransitions.get(i).setCanRemoveViews(canRemoveViews); } } @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 TransitionSet clone() { TransitionSet clone = (TransitionSet) super.clone(); clone.mTransitions = new ArrayList