Hello everyone! This is the last article of this series. In the first one, we covered animations, and in the second one, we talked about gestures. Now, we will combine gestures and animations in Jetpack Compose to build a drag to reorder feature in a list. That’s the preview:

If you want to follow along or want the code of the UI, check out this repository:

Note that compose version is 1.0.0

This is a synopsis of this article:

  1. When an item is being dragged, we make it in front of the others, draw a shadow behind it and rotate it.
  2. Using the y-axis offset that defines the distance between the first and the current position, we update the items states to either slid to the top, slid to the bottom, or not slid.
  3. When the item is placed, we want to launch a stream of particles to express better that the slot is put.

1. Drag to reorder

1.1. Current item

The skeleton of the dragToReroder function would be the same as the swipeToDelete that we implemented in the last article. That is an extension compact function that wraps pointerInput(Unit) and offset() in Modifier.composed().

Modifier.composed() is used to implement stateful modifiers that have instance-specific state for each modified element, allowing the same Modifier instance to be safely reused for multiple elements while maintaining an element-specific state.

Since we want to drag the item freely, we will create horizontal and vertical offsets that are animating while changing the item position. And when it is released, we animate these offsets to the initial position, zero that is.

In the ShoesCard Composable, we want to create a boolean state informing us if the item is being dragged or not so that we can’t rely on it as a condition to swing between values to show if the item is held.
To make the current item on top of others, we can make use of Modifier.zIndex().

Modifier.zIndex() Creates a modifier that controls the drawing order for the children of the same layout parent. A child with a larger zIndex will be drawn on top of all the children with a smaller zIndex. The default zIndex is 0.

Not to forget to mention, we want to rotate the item on being dragged, and show a shadow behind the slot child.

1.2. Other items

We want to map each shoes’ article to a state representing if the item is either in its place or swiped towards the top or the bottom.

After creating this map, we want to pass it to the ShoesList Composable where we provide every ShoesCard with its proper SlideState.

And inside the card, we animate its vertical translation based on the given slide state.

Next, we need to prepare two callbacks that will help us update outside references from each item. The first one is to modify a SlideState based on a ShoesArticle. The other one is changing the item position in shoesArticles when it’s placed, and update every slide state to SlideState.NONE.

Now, inside ShoesCard composable, we will pass updateSlideState() callback to Modifier.DragToReroder() to use it later and call updateItemPosition() when the item is placed.

Finally, we have to implement the algorithm that will trigger items to be slid. While the item is being dragged, we will use the y-axis offset to calculate the number of items that should be slid and we will update their state accordingly. We want to keep track of the previous number of items because when the new value is less than the last we should update the latter’s state to none.

2. Stream of particles

Now, we want to spice things up a little bit. We want to express that the dragged item is placed more explicitly. So, we decided that adding a stream of particles that emanates from the item’s bottom corners would be favorable. Let’s start by interpreting how we’re going to position a particle:

The big dashed black box is the one that refers to the item, and the violet represents the slot. Thus, we will call the distance between them slotItemDifference. Now, to translate the particle from position 1 to 2, we would horizontally translate it by its radius and we would vertically translate it by the accumulation of its radius, item’s height minus slotItemDifference, and particlesStreamRadius, which is the one indicating the radius of the dashed circle in the figure above.

We will use polar coordinates to move a particle along a given radius and rotation. We want a few dependencies in our function, so we want to make them global.

Finally, that’s how we’re going to create our two streams of particles.

3. External links and source code

Animation | Jetpack Compose | Android Developers

Here is the full Github repository for this article:

That’s it for this series. I hope it was beneficial for you.

Become Author

We are making content on new declarative UI kit Jetpack Compose, if you are willing to build content join us and we will help you get started.

Here We Go Again : (

if (article == helpful) {
    println("Like and subscribe to blog newsletter.")
} else {
    println("Let me know what i should blog on.")
}

This site uses Akismet to reduce spam. Learn how your comment data is processed.