What are all these dang Transitions?

I’ve seen a few questions about the Transitions used in Activity Transitions and Fragment Transitions and I thought I’d clear up their meanings.

In Activity Transitions, some Transitions are executed in the calling Activity and some are executed in the called Activity. Let’s see the simplest case and describe what is going on.

I’ve slowed down all animations on my device by 5x so that you can see what’s going on easier. There are two Activities, one with “Hello world” and one showing “Goodbye, cruel world!” One of the “Hello world” TextViews is shared to the Goodbye Activity. This app uses the default Material Theme — what is going on?

In the calling Activity, no Transition is being run. What?!? That can’t be. The Views from hello are clearly being faded out. What is happening is that the goodbye Activity is being brought on top of the hello Activity. Its background is being faded in on top of hello Activity and it appears as if the hello Activity is being faded out. You can adjust the duration of this fade by calling:

getWindow().setTransitionBackgroundFadeDuration(millis);

or in the window style:

<item name="windowTransitionBackgroundFadeDuration">500</item>

These should be called on the called (goodbye) Activity’s Window.

In the called Activity (goodbye), the “Goodbye, cruel world!” Views are faded in. This Transition is the Enter Transition and Material defaults this to Fade.

The shared element TextView “Hello, world!” is being moved using the shared element enter transition. In Material themes, this defaults to a combination of ChangeBounds, ChangeTransform, ChangeImageTransform, and ChangeClipBounds. These are generally a good starting point for most shared elements, moving and resizing the shared element.

Now, when going back, we want to play the transitions backwards. The enter transition is replaced with the return transition. The shared element enter transition is replaced with the shared element return transition. By default, these will just use the enter versions. In many cases, this is fine, but you may need to adjust the timing between entering and returning — either offsetting start delays or changing the interpolator to accelerate instead of decelerate or similar.

When going back, the background of the goodbye Activity fades out while the “Goodbye, cruel world!” Views Fade, following the return transition. The “Hello, world!” View moves to the position in the hello Activity following the shared element return transition.

So far, we’ve covered:

  • shared element enter
  • enter
  • shared element return
  • return

Let’s work on exit/reenter Transitions next:

Here, you can see that the “Hello, world” TextViews as well as the Action Bar move out of the hello Activity with an Explode Transition. The epicenter of the explosion is the shared element, the top-left “Hello, world” text. On the way back, I chose to use a different transition, Slide, to bring the Views back into the Activity. In my theme, I made these two additions:

<style name="AppTheme" parent="android:Theme.Material.Light">
  <item name="android:windowExitTransition">@android:transition/explode</item>
  <item name="android:windowReenterTransition">@android:transition/slide_bottom</item>
</style>

The exit transition is used to transition Views out of the calling Activity during the transition. The return transition is used to transition Views back into the Activity. These are used in the calling Activity.

The final transitions, shared element exit/return, are a little different. These are used in the calling Activity to execute a Transition before the shared element is transferred. Let’s make the TextView lift up off the hello Activity, before moving to the new goodbye Activity. Then the goodbye Activity will drop it when it reaches its destination.

I’ve made the background of the shared element “Hello, world” white so that you can see it a little better and distinguish the shadow. Setting a background on a View means that I get a shadow when I change the translation Z.

I’ve updated my transition definitions in the theme to use some custom transitions:

<style name="AppTheme" parent="android:Theme.Material.Light">
 <item name="android:windowExitTransition">@android:transition/explode</item>
 <item name="android:windowSharedElementExitTransition">@transition/shared_element_exit</item>
 <item name="android:windowSharedElementEnterTransition">@transition/shared_element_enter</item>
 <item name="android:windowSharedElementReenterTransition">@transition/shared_element_enter</item>
 <item name="android:windowSharedElementReturnTransition">@transition/shared_element_exit</item>
 <item name="android:windowReenterTransition">@android:transition/slide_bottom</item>
</style>

And I now have two new transitions, shared_element_enter:

<?xml version="1.0" encoding="utf-8"?>
<transitionSet
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:transitionOrdering="sequential">
 <changeBounds/>
 <transition class="com.sample.simpletransitions.ShadowTransition"
             android:duration="150"/>
</transitionSet>

and shared_element_exit:

<?xml version="1.0" encoding="utf-8"?>
<transitionSet
   xmlns:android="http://schemas.android.com/apk/res/android"
   android:transitionOrdering="sequential">
 <transition class="com.sample.simpletransitions.ShadowTransition"
             android:duration="150"/>
 <changeBounds/>
</transitionSet>

Note the timing. I want the lift to happen first, then move, then drop.

I have a very simple custom Transition for translation z. You’ll see it in the project.

Now, when I launch the goodbye Activity, I have to call setTranslationZ to trigger the shared element exit Transition:

startActivity(intent, options.toBundle());
hello.setTranslationZ(16);

Now, on the way back, there is nothing telling the system to put the shared element back to zero elevation, so I need to force that. I chose to use the SharedElementCallback. You could also use a TransitionListener on the share element reenter Transition.

setExitSharedElementCallback(new SharedElementCallback() {
  @Override
  public void onSharedElementEnd(List<String> sharedElementNames,
      List<View> sharedElements, List<View> sharedElementSnapshots) {
    findViewById(R.id.hello).setTranslationZ(0);
  }
});

Now we have an active shared element exit transition.

In summary, these are called in the calling Activity (e.g. hello):

  • exit transition – removes Views from the calling Activity (e.g. explode)
  • reenter transition – moves Views back into the calling Activity when returning (e.g. slide). Defaults to exit transition.
  • shared element exit transition – additional Transition to execute before transferring the shared element to the called Activity. Does not have to be on the shared element! In my example, this lifts the shared element off the hello Activity.
  • shared element reenter transition – when coming back, this is used after the shared element has been transferred back to the calling Activity. In my example, this drops the shared element back into the hello Activity. Defaults to shared element exit transition.

In the called Activity (e.g. goodbye):

  • enter transition – moves Views into the called Activity (e.g. fade)
  • return transition – moves Views out of the called Activity when going back. Defaults to the enter transition.
  • shared element enter transition – moves shared elements from the location/size in the calling Activity to the final location/size.
  • shared element return transition – when going back, moves the shared elements from the location/size in the called Activity to the location/size in the calling Activity. Defaults to shared element enter transition.

All of these transitions are the same in Fragment Transitions except that there are no shared element exit and shared element return transitions. Fragment Transitions work using the FragmentTransaction. You remove a Fragment, then add a Fragment, and the Transitions are activated. If you remove a Fragment, it sure is difficult to do some manipulation on it like you would in the Activity Transition. Instead, you’re going to have to do your manipulations before starting the FragmentTransaction.

Here is the code I used in the examples.

 

 

2 thoughts on “What are all these dang Transitions?

  1. For some reason both the SharedElementEnterTransition and SharedElementReturnTransition listeners are getting called when going from Activity A to B. I thought only the SharedElementEnterTransition listener should be called. How do you fix this?

    • That is because the same transition is used for the enter and return transitions. In the documentation “If nothing is set, the default will be to use the same value as set in setEnterTransition(android.transition.Transition).” If you want to have a separate return transition, you can give it its own value.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s