Fragment Transitions with Shared Elements using Android Navigation

Code on the Rocks
4 min readFeb 24, 2020

--

Anyone that isn’t using the newest Android Studio tools should definitely change that, especially if that means they aren’t using Android Jetpack’s Navigation component. This component makes maneuvering through the screens of your app a breeze and its chock full of features that can be used to make the navigation itself appear elegant. In this article I’ll be explaining how you can use the navigation component to create transitions with shared elements.

Shared Elements

What are shared elements? In the singular sense, a shared element is a pair of views that are present in two different fragments or activities. These views display the same information, such as a string or an image, but they may have different sizes or locations on screen. To give the the user the illusion that the view is being preserved during navigation, a transition is used to move and reshape the first view so that it “becomes” the second view. Since shared elements actually consist of two different views, they are technically not shared between destinations.

A shared element consists of 2 views that display the same information

Setup

We’ll be creating an app that performs a simple transition from one fragment to another with multiple shared elements. In Android Studio, create a new project using the “Bottom Navigation Activity” project template.

File -> New -> New Project -> Bottom Navigation Activity

This template gets us up and running pretty quick since there is already a navigation action between HomeFragment and HomeSecondFragment.

In addition to the basic project setup, you should also verify the following items are checked off:

implementation 'androidx.navigation:navigation-fragment-ktx:2.2.1'
implementation 'androidx.navigation:navigation-ui-ktx:2.2.1
  • Enable window content transitions in style.xml
<item name="android:windowActivityTransitions">true</item>
  • Create a new transition folder in app/res.

Right-click on the res folder -> New -> Android Resource Director

resource type = transition

  • Create a new transition resource in the transition folder (change_bounds.xml):
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
<changeBounds/>
</transitionSet>

ChangeBounds Transition — Single View

Now that everything’s set up, let’s work on executing a simple shared element transition with one TextView. Add one TextView to HomeFragment and one TextView to HomeSecondFragment. Move them to different locations on screen, constrain them each appropriately, and make them say the same thing (ex. “Example”).

fragment_home.xml (left) and fragment_second_home.xml (right)

If we navigate between these two fragments as is, there is no way to know that the first TextView is associated with the second TextView. For this reason, we need to add the android:transitionName property to both TextViews. All shared elements require unique transitionNames. Note that the transitionName property will not be available if windowActivityTransitions are not enable in your theme.

Add the transitionName property to the destination TextView

Now, in the onClickListener in HomeFragment, create a new val extras that maps the view in the starting fragment to the view in the destination fragment (textView to “exampleText”). Then, pass the extras argument to the navigate method of the navController.

The last step is to handle the incoming shared element in the destination fragment. To do this, we set sharedElementEnterTransition to the change_bounds.xml transition we created earlier. Add the same thing for sharedElementReturnTransition so that the transition works in the reverse direction.

With that, BAM! Transition works like a charm. You can move the TextViews anywhere on screen and it will still work fine.

Shared Element transition (enter and return)
The transition still works

Although not totally related to this tutorial, you need to add this line to MainActivity.kt to make the back button in the upper left corner work properly:

override fun onSupportNavigateUp() = findNavController(R.id.nav_host_fragment).navigateUp()

ChangeBounds Adjustments

You can also apply a ChangeBounds transition using the following code:

sharedElementEnterTransition = ChangeBounds().apply {
duration = 750
}

Using this method, you can adjust specific aspects of the transition.

ChangeBounds Transition-Nested View

A shared element nested inside another view (such as a CardView or a ConstraintLayout) will not transition properly if the parent view is not also treated as a shared element. For example, if our TextView is nested inside a ConstraintLayout in fragment 1 and we do not map the ConstraintLayout to the destination fragment, we get something super choppy like this:

To fix this, the parent View also needs to be transitioned. Using the same ConstraintLayout example, the proper way to make the transition is to map the ConstraintLayout from the first fragment to the root ConstraintLayout in the second fragment like this:

Child and Parent Views need to be transitioned

In conclusion, Shared Elements are pretty simple to use but there are a few gotchas that can make creating transitions a troubleshooting marathon. Code carefully!

--

--

No responses yet