Add dynamic scene creation/transition capability

Add TransitionManager.beginDelayedTransition() to handle starting a transition
on the next frame for a given scene root based on all changes that
take place between the first call to that method and the next animation frame.

Issue #9321937 Transitions: consider batching up multiple scene actions

Change-Id: I3fc92b6b4ec5ff42b1e678bcfd385703e32eba2a
This commit is contained in:
Chet Haase
2013-06-10 13:00:06 -07:00
parent 6b1d5a4ff2
commit 4f5072327d
5 changed files with 162 additions and 16 deletions

View File

@@ -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);

View File

@@ -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<Scene, ArrayMap<Scene, Transition>>();
static ArrayMap<ViewGroup, Transition> sRunningTransitions =
new ArrayMap<ViewGroup, Transition>();
private static ArrayList<ViewGroup> sPendingTransitions = new ArrayList<ViewGroup>();
/**
/**
* 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.
*
* <p>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.</p>
*
* <p>Passing in <code>null</code> for the transition parameter will
* cause the TransitionManager to use its default transition.</p>
*
* @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);
}
});
}
}
}

View File

@@ -212,6 +212,13 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:label="DelayedTransition"
android:name="DelayedTransition">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/container">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button1"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button2"/>
</LinearLayout>

View File

@@ -0,0 +1,66 @@
/*
* 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 com.android.transitiontests;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.transition.TransitionManager;
import android.widget.Button;
import android.widget.LinearLayout;
import static android.widget.LinearLayout.LayoutParams;
public class DelayedTransition extends Activity {
private static final int SEARCH_SCREEN = 0;
private static final int RESULTS_SCREEN = 1;
ViewGroup mSceneRoot;
static int mCurrentScene;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.two_buttons);
final Button button1 = (Button) findViewById(R.id.button1);
final Button button2 = (Button) findViewById(R.id.button2);
final LinearLayout container = (LinearLayout) findViewById(R.id.container);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int buttonWidth = button1.getWidth();
int containerWidth = container.getWidth();
if (buttonWidth < containerWidth) {
TransitionManager.beginDelayedTransition(container, null);
button1.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT));
TransitionManager.beginDelayedTransition(container, null);
button2.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT));
} else {
TransitionManager.beginDelayedTransition(container, null);
button1.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
TransitionManager.beginDelayedTransition(container, null);
button2.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
}
}
});
}
}