Skip to content

Shared Element Transition

Gonzalo Nardini edited this page Dec 25, 2015 · 2 revisions

Shared Element Transition

Let's start by how it looks!

matchlog animation

As can be seen in the GIF, we can make any element/s shared by two activities move from the starting position in the first one to the ending position in the second one, making the transition between both of them more fluid.

Fortunately, Android has a framework that allows us to achieve this type on animations with little work, and to make this even easier, there's a Builder class on NavigationUtils that facilitates this for us.

Create a NavigationUtils.Builder

To make an animation we can use the NavigationUtils.Builder class, that uses the Builder pattern and gives us a readable easy to use API to use these animations. There are a few methods:

  • setClass(Class clazz) Sets the activity to be opened. This is the only mandatory field, if it's not called a RuntimeException will be thrown.
  • addSharedElement(View sharedView, String sharedString) Adds a shared element. The sharedView is the view from the first activity to be animated and the sharedString is the string which was given to the view on the second activity as transitionName (more on this later).
  • addExtra(String reference, Serializable object) or addIntentObject(IntentObject intentObject) Adds an extra to be sent in the intent that opens the activity.
  • jump() Fires the created intent and opens the new activity with an animation (or normally if addSharedElement was never called)

Example (from the GIF on top)

new NavigationUtils.Builder(getActivity())
    .setClass(FinishedMatchActivity.class)
    .addSharedElement(viewHolder.mAvatar,
        getString(R.string.transition_player_avatar))
    .addSharedElement(viewHolder.mName,
        getString(R.string.transition_player_name))
    .addSharedElement(viewHolder.mMatchDetails,
        getString(R.string.transition_match_log_details))
    .addExtra(Extras.MatchLog.MATCH_LOG, matchLog)
    .jump();

Return animation

With the code above the animation from the first activity to the second will show. If we also want the reverse animation when returning, instead of calling Activity.finish() we must call Activity.supportFinishAfterTransition() to destroy the activity and go back.

Setting up the views

In order for the framework to know which two views are the shared ones, an attribute must be given to them in the XML code, android:transitionName="@string/transition_name" This transition name is the same we must then pass as parameter to the NavigationUtils.Builder when calling addSharedElement(View sharedView, String sharedString). The sharedString must be the same as the android:transitionName. A setter method also exists to set the transition name programmatically if necessary.

If the sharedString passed is null, sharedView.getTransitionName() will be used, which means both views would need to have the same transition name.

Setting up the App Theme

The last thing missing is to set up our default theme on styles.xml. All of this works only on API level 21 or above, which means we have to create a separate styles xml file under the folder values-v21. The styles.xml there must look something like this:

    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        
        ...

        <item name="android:windowContentTransitions">true</item>

        <item name="android:windowAllowEnterTransitionOverlap">false</item>
        <item name="android:windowAllowReturnTransitionOverlap">false</item>
        <item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
        <item name="android:windowSharedElementExitTransition">@android:transition/move</item>

    </style>

The only mandatory item is the first one, android:windowContentTransitions as true, but the others can let us customize animations of all the app. There are more as well that can be looked up and added if wanted.

Extra Considerations

That's pretty much it! Following everything above you should be able to make shared element transitions between activities.

Some custom views in some libraries can cause trouble though. A perfect example of this is the SimpleDraweeView of Fresco that we use so much. Since it overrides some methods from ImageView it doesn't work out of the box. However, there's an easy fix that involves extending the class and overriding a method. I called it TranslateDraweeView and the code for it can be found in this gist

There can also be trouble if trying to animate TextViews of different text size. A possible solution for it has been posted on Stack Overflow that can be checked out if something like this is needed.

Sources

Android Transition Framework
Material Animations Gist by lopspower

Clone this wiki locally