Android Tutorial

User stack animation in Jetpack Compose

There is a lot behind what you see!

Saurabh Pant
ProAndroidDev
Published in
4 min readJun 18, 2023

--

In this tutorial, I’ll show you how can you create an user stack animation as shown below

Well, if you look at this animation it seems like a vertical list of user pictures collapses into a horizontal list and all gets overlapped with each other. We’ve seen such stacking on Jira dashboards 😄.

Can we use Row and Column?

My first thought actually was of converting Column into Rows and vice versa but immediately realisation hit and it seems like a bad idea because then we would have to manage shifting the items from column to row along with animation and visibilities and I’m not sure how easy it would be.

Hence that approach was dropped.

Stack approach

The actual approach used in this is stacking all the items one over the other first and then altering their offsets as per their position and put them in the right location on screen.

Let’s consider if the item is of size 50dp, then on the vertical arrangement, the items are placed simply with top margin equal to their index multiplied with 50dp as shown in the diagram.

Calculation for vertical alignment

Coding the animation

Let’s begin by setting up the vertical arrangement of items. Simply take a box and and for each user calculate its offsetX and offsetY as show above in the diagram.

This will give us our vertical arrangement. Now lets settle our horizontal arrangement by tweaking the offsets calculation as follows

var isHorizontal by remember {
mutableStateOf(false)
}
...

val offsetX = (screenWidth - 25.dp) / 2 + if (isHorizontal) (index * 25).dp else 0.dp
val offsetY = ((screenHeight - 25.dp) / 2) + if (isHorizontal) 0.dp else (index * 50).dp

...

What we did here was created a isHorizontal variable which toggles when we click on the button to change the arrangement.

We added screen width and height portion in calculation just to bring the view into centre and it is not necessary.

For vertical arrangement, we increase the y coordinate by index times 50dp.

For horizontal arrangement, we increase the x coordinate by index times 25dp (50dp % 2).

By far, what we get it as below

Cool. But what is missing here is the smooth transition from one arrangement to the other. So let’s add that too. In order to do that we need to make our offsets to transition from their last value to the new value. Also setting these new offsets in our modifier as follows

// new offsetX
val targetCordX by animateDpAsState(
targetValue = offsetX,
animationSpec = tween(
easing = easing,
durationMillis = animationDuration
)
)
// new offsetY
val targetCordY by animateDpAsState(
targetValue = offsetY,
animationSpec = tween(
easing = easing,
durationMillis = animationDuration
)
)

val modifier = Modifier
.size(50.dp)
.absoluteOffset(
x = targetCordX, // offsetX -> targetCordX
y = targetCordY, // offsetY -> targetCordY
)

We simply animate our offsets as dp with new offsets values every time the arrangement is toggled. Now the result looks like this:

Whoa! We can see it is working as expected. Only one part is yet to be done. The last item in the stack hides for horizontal arrangement and shows up again for vertical and that too with an animation. So let’s do that too.

To make the last item hide/show, we simply add the condition that if the arrangement is horizontal and index is the last one then hide it otherwise show it.

val lastElementVisibility = if (isHorizontal && index == userImages.lastIndex) 0f else 1f 

Now we create the alpha variable which will animate our visibility across the transitions as follows

val alpha by animateFloatAsState(
targetValue = lastElementVisibility,
animationSpec = tween(
easing = easing,
durationMillis = animationDuration
)
)

val modifier = Modifier
.size(50.dp)
.absoluteOffset(
x = targetCordX,
y = targetCordY,
)
.alpha(alpha) // affects the visibility along the transition

Credits

The reference for this animation is taken from LinkedIn where it is created in flutter.

That is all for now! Stay tuned!

Connect with me (if the content is helpful to you ) on

Until next time…

Cheers!

--

--

App Developer (Native & Flutter) | Mentor | Writer | Youtuber @_zaqua | Traveller | Content Author & Course Instructor @Droidcon | Frontend Lead @MahilaMoney