Upcoming and OnDemand Webinars View full list

Building Animations with the android.transition Framework, Part 2

Bolot Kerimbaev

In the previous post, we took a first look at the [android.transition](http://developer.android.com/reference/android/transition/package-summary.html) framework and started following the evolution of our AndroidTransitionExample project. In this post, we’ll continue our exploration by learning how to control transitions and how to load them from XML files.

To try out the example project, follow the instructions in the previous post under “Following along with Git.” The inset text below gives additional pointers.

Controlling Transitions

Let’s look at controlling transitions. First, we’ll refactor a bit and extract the goToScene method, instead of calling TransitionManager.go() directly:

...
    goButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            TransitionManager.go(scene);
            goToScene(scene);
        }
    });
...

private void goToScene(Scene scene) {
    ChangeBounds changeBounds = new ChangeBounds();
    Fade fadeOut = new Fade(Fade.OUT);
    Fade fadeIn = new Fade(Fade.IN);
    TransitionSet transition = new TransitionSet();
    transition.setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
    transition
            .addTransition(fadeOut)
            .addTransition(changeBounds)
            .addTransition(fadeIn);
    TransitionManager.go(scene, transition);
}

Jump to “extract method goToScene”:
git checkout 6ea37f7

The effect is still the same. In fact, it’s identical to using AutoTransition. However, this approach gives us more control, since we can tweak the components of the transition set to our liking. For example, we could change the duration of some animations:

private void goToScene(Scene scene) {
    ChangeBounds changeBounds = new ChangeBounds();
    changeBounds.setDuration(1000);
    Fade fadeOut = new Fade(Fade.OUT);
    fadeOut.setDuration(1000);
    Fade fadeIn = new Fade(Fade.IN);
    fadeIn.setDuration(1000);
    TransitionSet transition = new TransitionSet();
    transition.setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
    transition
            .addTransition(fadeOut)
            .addTransition(changeBounds)
            .addTransition(fadeIn);
    TransitionManager.go(scene, transition);
}

Jump to “slow motion transitions”:
git checkout fbcc465

For some reason, the animation controls in Developer Options don’t seem to influence transition animations. The above code allows us to look at the animations in slow motion.

We can control more than just duration of these transitions. One interesting thing to try is adding an interpolator. One of the principles of classical animation states that characters cannot simply start moving. They have to show anticipation, then perform the movement and finally overshoot before coming to a stop. Using a built-in AnticipateOvershootInterpolator, we can achieve the desired effect. Note that we slowed down the change bounds animation, so that it’s easier to see.

ChangeBounds changeBounds = new ChangeBounds();
changeBounds.setInterpolator(new AnticipateOvershootInterpolator());
changeBounds.setDuration(2000);
Fade fadeOut = new Fade(Fade.OUT);

Jump to “use AnticipateOvershootInterpolator”:
git checkout 1de57f0

If you try pressing the “Perform the transition” button after the transition to the second scene, you’ll discover that it doesn’t do anything. That’s because the only button we wired up with an OnClickListener is the button in the first layout. To make the second scene’s button work, we have to load the scene differently:

View rootView = inflater.inflate(R.layout.fragment_transition_scene_1,
        container, false);
final Scene scene = Scene.getSceneForLayout(container,
        R.layout.fragment_transition_scene_2, getActivity());
View secondView = inflater.inflate(R.layout.fragment_transition_scene_2,
        container, false);
final Scene scene = new Scene(container, (ViewGroup)secondView);
Button goButton = (Button)rootView.findViewById(R.id.goButton);

Now that we have the secondView, we can wire up the second button:

final Scene originalScene = new Scene(container, (ViewGroup)rootView);
Button goBackButton = (Button)secondView.findViewById(R.id.goButton);
goBackButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        goToScene(originalScene);
    }
});

This is what the final result looks like:

Jump to “add the return transition”:
git checkout 9871bfa

Transitions in XML

So far, we’ve looked at using the transition framework in code. However, it is also possible to create transitions in XML. KitKat introduces the new resource folder transition, which holds XML files that define transitions and even the mapping of scenes.

For example, defining our custom transition in XML would look like this (using slow_auto_transition.xml):

<transitionSet
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:transitionOrdering="sequential">
    <fade
        android:fadingMode="fade_out"
        android:duration="1000"/>
    <changeBounds
        android:duration="2000"
        android:interpolator="@android:interpolator/anticipate_overshoot"/>
    <fade
        android:fadingMode="fade_in"
        android:duration="1000"/>
</transitionSet>

Using the XML file would simplify our goToScene method:

private void goToScene(Scene scene) {
  TransitionInflater inflater = TransitionInflater.from(getActivity());
  Transition transition
      = inflater.inflateTransition(R.transition.slow_auto_transition);
  TransitionManager.go(scene, transition);
}

Run the project now, and the result is exactly the same as before.

Jump to “inflate the transition from the XML file”:
git checkout c2a25d4

Transition Manager in XML

As mentioned above, it is also possible to inflate an entire transition manager instance from XML, which would define transitions for going from one scene to another. We’ll make the final change to our project. Here’s the new transition_manager.xml file:

<transitionManager
    xmlns:android="http://schemas.android.com/apk/res/android">
    <transition
        android:fromScene="@layout/fragment_transition_scene_1"
        android:toScene="@layout/fragment_transition_scene_2"
        android:transition="@transition/slow_auto_transition"/>
    <transition
        android:fromScene="@layout/fragment_transition_scene_1"
        android:toScene="@layout/fragment_transition_scene_2"
        android:transition="@transition/slow_auto_transition"/>

We’ll also modify our layouts so that we don’t have to connect the buttons in code: add android:onClick="goToScene2" to the goButton in the first layout and android:onClick="goToScene1" in the second layout.

    <Button
        android:id="@+id/goButton"
        android:text="@string/button_go"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="goToScene2"

We’ll move most of the code into the TransitionActivity and the TransitionFragment will be left with just loading the view:

public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View rootView = inflater.inflate(
                        R.layout.fragment_transition_scene_1, container, false);
    return rootView;
}

Add the instance variables to TransitionActivity:

private TransitionManager mTransitionManager;
private Scene mScene1;
private Scene mScene2;

Add the following code at the end of TransitionActivity.onCreate:

ViewGroup container = (ViewGroup)findViewById(R.id.container);
TransitionInflater transitionInflater = TransitionInflater.from(this);
mTransitionManager = transitionInflater.inflateTransitionManager(
                        R.transition.transition_manager, container);
mScene1 = Scene.getSceneForLayout(container,
                        R.layout.fragment_transition_scene_1, this);
mScene2 = Scene.getSceneForLayout(container,
                        R.layout.fragment_transition_scene_2, this);

And finally, add the following two methods to TransitionActivity:

public void goToScene1(View view) {
    mTransitionManager.transitionTo(mScene1);
}

public void goToScene2(View view) {
    mTransitionManager.transitionTo(mScene2);
}

The final result is still the same.

Jump to “load the transition manager from the XML file”:
git checkout cc40873
or
git checkout master

Enjoy the transitions!

Not Happy with Your Current App, or Digital Product?

Submit your event

Let's Discuss Your Project

Let's Discuss Your Project