Android shared element transitions

In this post we will look at how you can create shared element transitions in the android framework. You can see a simple project making use of shared element transitions here.

The first thing we'll need to do is make sure that our project supports transitions. We can do this by making sure that we are using the AppCompat theme and that we have a device running at least lollipop. That will ensure that our theme has the following property:

<item name="windowActivityTransitions">true</item>

If you are not using the AppCompat theme then you will need to make sure that you set that property in your app theme or in the theme for any activity that you wish to have participate in transitions.

Once we have a project that supports activity transitions we can decide which elements we want to have "transition" from one activity to another. In the sample project linked above we will be creating a shared element transition that includes an ImageView and a TextView.

The application's initial activity will show you a list of football teams. Each team's crest and name will be displayed as an item in a recyclerview.

If you tap on an item in the list then you will be taken to a second activity showing you the details for that team. The team's name will appear in the actionbar and the team crest will appear larger and more prominently at the top of the activity.

Our transition will show the team name and crest smoothly move into place from the tapped list item to their resting places inside the detail activity.

In our layout file for a team list item we will need to give the ImageView and TextView the android:transitionName property. This will need to be a unique string that can be used to identify the view during the transition. We will need to use the same strings to identify the ImageView and TextView in our second activity so that android knows how to transition the element from one screen to the next.

Here is what our view xml looks like in the team list item

<ImageView
            android:id="@+id/team_crest_image_view"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:transitionName="@string/team_crest_image_view"
            android:layout_gravity="start|center_vertical"
            android:scaleType="centerInside"/>


<TextView
            android:id="@+id/team_name_textview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="56dp"
            android:layout_gravity="center_vertical"
            android:transitionName="@string/team_name_text_view"
            android:text="@{team.name}"
            tools:text="Hull City"/>

Here is what our view xml looks like in our second activity


<android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <android.support.v7.widget.Toolbar
                android:id="@+id/fragment_toolbar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:title="@{teamItem.name}"
                android:transitionName="@string/team_name_text_view"
                app:titleTextColor="@android:color/white"/>


            <ImageView
                android:id="@+id/team_crest_image_view"
                android:layout_width="250dp"
                android:layout_height="250dp"
                android:layout_gravity="center"
                android:adjustViewBounds="true"
                android:scaleType="centerInside"                android:transitionName="@string/team_crest_image_view"/>

        </android.support.design.widget.AppBarLayout>

You can see that in both layout files we have made sure the "matching" elements have the same android:transitionName. Now when we perform the transition android will automatically create a smooth transition for these two elements from one screen to the next.

So how do we make the shared element transition happen? Well we have to write a little code. In our click handler when we prepare to launch the next activity we will need to provide a bundle that contains information about our shared elements.


Pair<View,String> crestImagePair = 
    new Pair<>(teamCrestImageView, teamCrestImageView.getTransitionName())

Pair<View,String> teamNamePair = 
    new Pair<>(teamNameTextView,teamNameTextView.getTransitionName()

Pair[] sharedElements = new Pair[]{ crestImagePair, teamNamePair};

        ActivityOptionsCompat options = makeSceneTransitionAnimation(getActivity(), sharedElements);

Intent launchIntent = 
    TeamDetailActivity.getLaunchIntent(getActivity(), teamsItem);

startActivity(launchIntent, options.toBundle());


First we create an array with two Pair<View,String> objects. Each of these pair objects contains a view we want to use in our shared element transition and the transition name for that view. Once we have the array ready we use ActivityOptionsCompat.makeSceneTransitionAnimation() to create an ActivityOptionsCompat object that contains all the secret sauce we need for our transition. Next when we launch our activity we use the toBundle() method of our ActivityOptionsCompat object and pass it in to the startActivity() method.

Now if the ImageView containing our team's crest was making use of static resources bundled with our app we would be done. The transition would simply happen for us and you would see our thumbnail crest image smoothly move and grow into position on our second activity. The real world is rarely that easy on us though. You will probably have some data that needs to be loaded asynchronously in the activity that you just launched and we can't smoothly transition until after that data is ready. That's ok though because android has our back with postponeEnterTransition(). In the activity that we are transitioning to we just make sure that the onCreate() method includes a call to postponeEnterTransition() and then proceed to load anything that we need as normal.

Once the data or other async process we needed to complete is finished, we can let the framework know to go ahead and run that transition with startPostponedEnterTransition()

In the example project we make use of glide to asynchronously grab the image from an API in our second activity. We make use of a glide listener to tell the activity to start the postponed transition in onResourceReady.

@Override
                public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
                    getActivity().startPostponedEnterTransition();
                    return false;
                }

Whether you are waiting on glide to load an image from a remote location or doing any other async work, you just need to remember to call startPostponedEnterTransition() when the work completes or else the system won't know that it is ok to draw your new activity.

One final thing you may wish to do is is include the status bar and system navigation bar in your shared element transition. This will prevent them from appearing to flash white briefly during the default fade transition that will happen along with your shared element transition.

The code to do that will look like this:

View statusBarBackground = getActivity().findViewById(android.R.id.statusBarBackground);
        View navigationBarBackground = getActivity().findViewById(android.R.id.navigationBarBackground);


Pair[] sharedElements = new Pair[]{new Pair<View, String>(teamCrestImageView, teamCrestImageView.getTransitionName()),
            new Pair<View, String>(teamNameTextView, teamNameTextView.getTransitionName()),
            new Pair<View,String>(statusBarBackground, Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME),
            new Pair<View,String>(navigationBarBackground, Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME)
        };

We include the two additional views in our shared elements array and that way they will not be faded in and out during the transition.

That concludes this brief tutorial on introducing shared element transitions to your android app. I have included a link to the android developer documentation along with an accompanying github project below.

Helpful links:

Example project

developer.android.com