Search code examples
androidanimationlazycolumn

The scope of animation with in LazyColumn Item view


I have a LazyColumn,and the item view has Image,button.at the bottom of page, it has a cart icon.so when click the button of item,image will be start an offset animation that adds the bottom shopping cart icon.but the scope of animation just within the item view.in effect,I hope the destination of animation is bottom of this page. because the cart icon is in the bottom of page, so, I don't know how to solve this problem, Any one help me? thanks a lot!

some code snippet:

@Composable
fun GoodsListView() {
    var itemAddedToCart by remember { mutableStateOf(false) }
    val cartPosition = remember { mutableStateOf(Offset.Zero) }
    val animatedOffset by animateOffsetAsState(
        targetValue = if (itemAddedToCart) cartPosition.value else Offset.Zero,
        animationSpec = tween(durationMillis = 1000, easing = FastOutSlowInEasing), label = ""
    )
    val scale by animateFloatAsState(
        targetValue = if (itemAddedToCart) 0f else 1f,
        animationSpec = tween(durationMillis = 1000, easing = FastOutSlowInEasing), label = ""
    )
    Column {
        LazyColumn(modifier = Modifier.weight(1f)) {
            items(list.size) {
                Row {
                    Image(
                        painter = painterResource(id = R.drawable.ic_mall_goods_default_icon), // the original of image
                        contentDescription = "Goods Cover",
                        modifier = Modifier.size(100.dp)
                    )
                    Box(
                        modifier = Modifier
                            .offset { IntOffset(animatedOffset.x.toInt(), animatedOffset.y.toInt()) }
                            .size(100.dp)
                            .graphicsLayer {
                                scaleX = scale
                                scaleY = scale
                            }
                    ) {
                        Image(
                            painter = painterResource(id = R.drawable.ic_mall_goods_default_icon), // the target of animation image
                            contentDescription = "",
                            modifier = Modifier.size(100.dp)
                        )
                    }
                    Button(onClick = {
                        if (!itemAddedToCart) itemAddedToCart = true
                    }) {
                        Text(text = "Add to cart")
                    }
                }
            }
        }
        Image(
            painter = painterResource(id = R.drawable.ic_mall_cart), // the destination of animation
            contentDescription = "Shopping Cart",
            modifier = Modifier
                .size(50.dp)
                .onGloballyPositioned { layoutCoordinates ->
                    cartPosition.value = layoutCoordinates.positionInRoot()
                }
        )
    }
}

I have no more experience with compose,so ask for here.


Solution

  • try this please:

    @Composable
    fun GoodsListView() {
        var itemAddedToCart by remember { mutableStateOf(false) }
    
        Column {
            LazyColumn(modifier = Modifier.weight(1f)) {
                items(list.size) { index ->
                    Column {
                        Row {
                            Image(
                                painter = painterResource(id = R.drawable.ic_mall_goods_default_icon),
                                contentDescription = "Goods Cover",
                                modifier = Modifier.size(100.dp)
                            )
                            Box(
                                modifier = Modifier
                                    .offset { IntOffset(animatedOffset.x.toInt(), animatedOffset.y.toInt()) }
                                    .size(100.dp)
                                    .graphicsLayer {
                                        scaleX = scale
                                        scaleY = scale
                                    }
                            ) {
                                Image(
                                    painter = painterResource(id = R.drawable.ic_mall_goods_default_icon),
                                    contentDescription = "",
                                    modifier = Modifier.size(100.dp)
                                )
                            }
                            Button(onClick = {
                                if (!itemAddedToCart) {
                                    itemAddedToCart = true
                                    val buttonPosition = LocalLayoutInfo.current.positionInRoot()
                                    val cartPosition = remember(index) { mutableStateOf(Offset.Zero) }
                                    val cartImage = LocalContext.current.resources.getDrawable(R.drawable.ic_mall_cart)
                                    val cartImageIntrinsicSize = cartImage.intrinsicWidth.toFloat() to cartImage.intrinsicHeight.toFloat()
                                    cartPosition.value = buttonPosition - Offset(0f, cartImageIntrinsicSize.second)
                                    animateOffsetAsState(
                                        targetValue = cartPosition.value,
                                        animationSpec = tween(durationMillis = 1000, easing = FastOutSlowInEasing),
                                        label = ""
                                    )
                                }
                            }) {
                                Text(text = "Add to cart")
                            }
                        }
                    }
                }
            }
            Image(
                painter = painterResource(id = R.drawable.ic_mall_cart),
                contentDescription = "Shopping Cart",
                modifier = Modifier
                    .size(50.dp)
                    .align(Alignment.BottomCenter) // Place the cart icon at the bottom
            )
        }
    }
    
    1. Use a Column as the parent layout for each item.

    Place the Image, Button, and the animating Box inside this Column. Position the shopping cart icon (Image) at the bottom of the entire LazyColumn using absolute positioning.

    1. Animation Target Calculation:

    Instead of storing the cartPosition directly, calculate the target offset for the animation dynamically within the item view. You can achieve this by using onGloballyPositioned on the Button inside the item view. Inside onGloballyPositioned, calculate the difference between the button's position and the shopping cart icon's position. This will be the target offset for the animation.