Reorderable icon indicating copy to clipboard operation
Reorderable copied to clipboard

How can we implement change order animations similar to AppleWallet?

Open anonym24 opened this issue 9 months ago • 1 comments
trafficstars

Here's the example how it works in AppleWallet: https://www.youtube.com/shorts/X-vcgG-WBCk

Basically the move animation happens like this: first the card smoothly moves down and then up

So I have made sample example with this library (edited a couple of code lines)


private val CARD_HEIGHT = 500.dp

@Composable
fun ScreenContent(modifier: Modifier = Modifier) {
    var items by remember { mutableStateOf((0..5).map { getRandomColor() }) }

    val lazyListState = rememberLazyListState()

    val cardPctHeight = 0.1f
    val cardLastPctHeight = 0.5f

    // https://github.com/Calvin-LL/Reorderable
    val reorderableLazyListState = rememberReorderableLazyListState(
        lazyListState = lazyListState,
        shouldItemMoveThreshold = (CARD_HEIGHT * cardPctHeight) / 2f // added new param to reorderable library
    ) { from, to ->
        items = items.toMutableList().apply {
            add(to.index, removeAt(from.index))
        }
    }

    LazyColumn(
        state = lazyListState,
        modifier = modifier.fillMaxSize(),
        contentPadding = PaddingValues(top = 10.dp),
        verticalArrangement = Arrangement.Bottom
    ) {
        itemsIndexed(
            items = items,
            key = { _, item -> item.toArgb() }
        ) { index, item ->
            ReorderableItem(reorderableLazyListState, key = item.toArgb()) {
                Box(
                    modifier = Modifier
                        .padding(horizontal = 10.dp)
                        .draggableHandle()
                        .layout { measurable, constraints ->
                            val placeable = measurable.measure(constraints)
                            val placeableHeight = if (index != items.lastIndex) {
                                placeable.height * cardPctHeight
                            } else {
                                placeable.height * cardLastPctHeight
                            }
                            layout(placeable.width, placeableHeight.roundToInt()) {
                                placeable.place(0, 0)
                            }
                        }
                        .fillMaxWidth()
                        .clip(RoundedCornerShape(12.dp))
                        .height(CARD_HEIGHT)
                        .background(color = item)
                ) {
                    //
                }
            }
        }
    }
}

private fun getRandomColor(): Color {
    return Color(
        red = Random.nextFloat(),
        green = Random.nextFloat(),
        blue = Random.nextFloat(),
        alpha = 1f
    )
}

full sample: https://github.com/anonym24/AppleWalletOrderChangeAnim/blob/main/app/src/main/java/com/example/applewalletorderchangeanim/MainActivity.kt

Right now it works like this with the default animation (animateItemModifier: Modifier = Modifier.animateItem()):

https://youtube.com/shorts/gMDc6acLGrg

or:

https://github.com/user-attachments/assets/b6fff423-4601-4aa5-9a3b-1f476af963de

So I made changes here to remove zIndex: https://github.com/anonym24/AppleWalletOrderChangeAnim/blob/main/app/src/main/java/com/example/applewalletorderchangeanim/ui/reorderable/ReorderableLazyList.kt#L209

Added new param here https://github.com/anonym24/AppleWalletOrderChangeAnim/blob/main/app/src/main/java/com/example/applewalletorderchangeanim/ui/reorderable/ReorderableLazyList.kt#L94

Because the last card has larger height, item.center.y had to be replaced

anonym24 avatar Feb 04 '25 11:02 anonym24