Search

Building Animations with the android.transition Framework, Part 2

Bolot Kerimbaev

5 min read

Feb 4, 2014

Building Animations with the android.transition Framework, Part 2

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!

Mark Dalrymple

Reviewer Big Nerd Ranch

MarkD is a long-time Unix and Mac developer, having worked at AOL, Google, and several start-ups over the years.  He’s the author of Advanced Mac OS X Programming: The Big Nerd Ranch Guide, over 100 blog posts for Big Nerd Ranch, and an occasional speaker at conferences. Believing in the power of community, he’s a co-founder of CocoaHeads, an international Mac and iPhone meetup, and runs the Pittsburgh PA chapter. In his spare time, he plays orchestral and swing band music.

Speak with a Nerd

Schedule a call today! Our team of Nerds are ready to help

Let's Talk

Related Posts

We are ready to discuss your needs.

Not applicable? Click here to schedule a call.

Stay in Touch WITH Big Nerd Ranch News