diff --git a/api/current.txt b/api/current.txt index 7907e563bae3b..b063fa76d1609 100644 --- a/api/current.txt +++ b/api/current.txt @@ -28512,6 +28512,7 @@ package android.view.transition { public class TransitionManager { ctor public TransitionManager(); + method public static void beginDelayedTransition(android.view.ViewGroup, android.view.transition.Transition); method public android.view.transition.Transition getDefaultTransition(); method public static void go(android.view.transition.Scene); method public static void go(android.view.transition.Scene, android.view.transition.Transition); diff --git a/core/java/android/view/transition/TransitionManager.java b/core/java/android/view/transition/TransitionManager.java index 4971a92466b35..8088f6b2c23da 100644 --- a/core/java/android/view/transition/TransitionManager.java +++ b/core/java/android/view/transition/TransitionManager.java @@ -19,6 +19,8 @@ import android.util.ArrayMap; import android.view.ViewGroup; import android.view.ViewTreeObserver; +import java.util.ArrayList; + /** * This class manages the set of transitions that fire when there is a * change of {@link Scene}. To use the manager, add scenes along with @@ -41,8 +43,10 @@ public class TransitionManager { new ArrayMap>(); static ArrayMap sRunningTransitions = new ArrayMap(); + private static ArrayList sPendingTransitions = new ArrayList(); - /** + + /** * Sets the transition to be used for any scene change for which no * other transition is explicitly set. The initial value is * an {@link AutoTransition} instance. @@ -142,24 +146,15 @@ public class TransitionManager { final ViewGroup sceneRoot = scene.getSceneRoot(); - Transition runningTransition = sRunningTransitions.get(sceneRoot); - if (runningTransition != null) { - runningTransition.cancelTransition(); - } - - // Capture current values - if (transition != null) { - transition.captureValues(sceneRoot, true); - } - - // Notify previous scene that it is being exited - Scene previousScene = sceneRoot.getCurrentScene(); - if (previousScene != null) { - previousScene.exit(); - } + sceneChangeSetup(sceneRoot, transition); scene.enter(); + sceneChangeRunTransition(sceneRoot, transition); + } + + private static void sceneChangeRunTransition(final ViewGroup sceneRoot, + final Transition transition) { if (transition != null) { final ViewTreeObserver observer = sceneRoot.getViewTreeObserver(); observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @@ -181,6 +176,25 @@ public class TransitionManager { } } + private static void sceneChangeSetup(ViewGroup sceneRoot, Transition transition) { + + Transition runningTransition = sRunningTransitions.get(sceneRoot); + if (runningTransition != null) { + runningTransition.cancelTransition(); + } + + // Capture current values + if (transition != null) { + transition.captureValues(sceneRoot, true); + } + + // Notify previous scene that it is being exited + Scene previousScene = sceneRoot.getCurrentScene(); + if (previousScene != null) { + previousScene.exit(); + } + } + /** * Change to the given scene, using the * appropriate transition for this particular scene change @@ -272,4 +286,47 @@ public class TransitionManager { scene.setEnterAction(action); changeScene(scene, transition); } + + /** + * Static utility method to animate to a new scene defined by all changes within + * the given scene root between calling this method and the next rendering frame. + * Calling this method causes TransitionManager to capture current values in the + * scene root and then post a request to run a transition on the next frame. + * At that time, the new values in the scene root will be captured and changes + * will be animated. There is no need to create a Scene; it is implied by + * changes which take place between calling this method and the next frame when + * the transition begins. + * + *

Calling this method several times before the next frame (for example, if + * unrelated code also wants to make dynamic changes and run a transition on + * the same scene root), only the first call will trigger capturing values + * and exiting the current scene. Subsequent calls to the method with the + * same scene root during the same frame will be ignored.

+ * + *

Passing in null for the transition parameter will + * cause the TransitionManager to use its default transition.

+ * + * @param sceneRoot The root of the View hierarchy to run the transition on. + * @param transition The transition to use for this change. A + * value of null causes the TransitionManager to use the default transition. + */ + public static void beginDelayedTransition(final ViewGroup sceneRoot, Transition transition) { + + if (!sPendingTransitions.contains(sceneRoot)) { + sPendingTransitions.add(sceneRoot); + if (transition == null) { + transition = sDefaultTransition; + } + final Transition finalTransition = transition; + sceneChangeSetup(sceneRoot, transition); + sceneRoot.setCurrentScene(null); + sceneRoot.postOnAnimation(new Runnable() { + @Override + public void run() { + sPendingTransitions.remove(sceneRoot); + sceneChangeRunTransition(sceneRoot, finalTransition); + } + }); + } + } } diff --git a/tests/TransitionTests/AndroidManifest.xml b/tests/TransitionTests/AndroidManifest.xml index be6b145e2bc7e..98174ab34e6ce 100644 --- a/tests/TransitionTests/AndroidManifest.xml +++ b/tests/TransitionTests/AndroidManifest.xml @@ -212,6 +212,13 @@ + + + + + + diff --git a/tests/TransitionTests/res/layout/two_buttons.xml b/tests/TransitionTests/res/layout/two_buttons.xml new file mode 100644 index 0000000000000..23d59f8584bd4 --- /dev/null +++ b/tests/TransitionTests/res/layout/two_buttons.xml @@ -0,0 +1,15 @@ + + +