Container Transform in Jetpack Compose

Add some delightful animations to your app with just a few lines of code

Introduction

In this article we will learn how to add container transform animations to our apps. The image below showcases what we will implement today:

Let's get started.

Dependencies

The APIs that we will be using today are part of the 1.7.0 alpha releases of Jetpack Compose, so we will need to update our dependencies file to select these alpha variants, as shown below

The composable elements

First we need to define the elements that compose this screen. We have three of them, the background list of users, the floating action button, and the input box to add new users. Let's look at each of them in turn.

The users list

The users list is not really relevant to the content transform animation, it's just there to add some purpose to the demo. This list is simply a LazyColum with user cards for each of the users, there isn't much to it, let's look at the code:

Let's have a look:

And that's it for the user list. This composable is very simple but that's all we need for our demo. Let's look next at the floating action button:

That's also pretty straightforward, we're simply leveraging the FloatingActionButton composable from the material library and adding an Add icon to it. We will flesh out the click handler later.

Next we have the input box, let's look at the code:

This composable is a bit larger, but there isn't much to it, let's have a look at the different elements:

And that's pretty much it for all the pieces of the demo app we need to showcase the container transform.

What we'll do next is put all the pieces together but without any animation, and then we'll add the container transform animation.

Adding it all together

First we will create the main composable that contains these 3 elements. For now we are just going to display all of them at once, without worrying about the logic to handle whether we are in the Fab mode or in the Add user mode. Let's see the code for our baseline:

If we run this, we get this result

Alright, we have all the pieces in place, let's add the animation.

To have access to the animation APIs we need to wrap the elements that will be animating in a SharedTransitionLayout - this composable exposes a scope, SharedTransitionScope, that will allow us to connect the 2 elements that we are using for the content transform animation. Within the SharedTransitionScope we have access to additional modifiers, similar to how within a Box we are in a BoxScope and can access Modifier.align. The Modifier that we want to use for the container transform is sharedBounds - when we want to animate between different kinds of content, as it's the case here, sharedBounds is the right choice. If, on the other hand we have a common element in the animation, like an image that changes size and position, then sharedElement would be the right choice.

The sharedBounds has 2 required arguments, the first is used to connect the elements that we are animating, and the second is an animated visibiliy scope that is the one responsible for the actual animation. For our animation, we will be using AnimatedContent - this composable provides the AnimatedVisibilityScope that we will pass to sharedBounds.  Within the AnimatedContent we will display either the Fab or the input box, and toggling what is being displayed will trigger the animation. Let's have a look at the code, it will become much clearer when we do so:

And that's it, with just a few lines of code we have added an engaging container transform to our app. In this demo we've used all the defaults for the animation, but both AnimatedContent and sharedBounds offer customization options that I encourage you to explore on your own time. The complete source code for this demo is available on this GitHub gist.