Search code examples
androidkotlinandroid-jetpack-composejetpack-compose-animationandroid-jetpack-compose-animation

Idomatic way of using animateDpAsState in padding jetpack compose


I am learning animateDpAsState from the doc. I did it without any problem, but I see a lot of recomposing happens. So I want to know what is the recommended way of doing this?

@Composable
private fun PaddingViewAnimation() {
    var visible by remember { mutableStateOf(true) }
    val iconOffsetAnimation: Dp by animateDpAsState(
        if (visible) 13.dp else 0.dp, tween(1000)
    )
    PaddingViewAnimationStateLess(
        { iconOffsetAnimation },
        visible,
        onVisibleChange = {
            visible = it
        }
    )
}

PaddingViewAnimationStateLess

@Composable
fun PaddingViewAnimationStateLess(
    iconOffsetAnimation: () -> Dp,
    visible: Boolean,
    onVisibleChange: (Boolean) -> Unit,
) {
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .padding(start = 16.dp, top = 16.dp)
    ) {
        Image(
            modifier = Modifier.padding(top = iconOffsetAnimation()),
            imageVector = Icons.Default.ShoppingCart,
            contentDescription = null,
        )
        Button(
            modifier = Modifier.padding(top = 10.dp),
            onClick = {
                onVisibleChange(!visible)
            },
        ) {
            Text(text = "Move Text")
        }
    }
}

When first time button click animation happens and I can see in layout inspector. I don't know this is normal or we can fix this problem. Thanks

enter image description here


Solution

  • Instead of animating the top padding, you can do something different applying a y-translation with the graphicsLayer modifier with the lambda block that causes the layer properties update without triggering recomposition and relayout.

    You can apply it to the Column or to each children.

    Something like:

    Column(
        modifier = Modifier
            .fillMaxWidth()
            .padding(start = 16.dp, top = 16.dp)
            .graphicsLayer { translationY = iconOffsetAnimation().toPx() }
    ) {
        Image(
            imageVector = Icons.Default.ShoppingCart,
            contentDescription = null,
        )
        //....
    }