How to measure height and apply in view jetpack compose

2.3k Views Asked by At

I want to measure the height of parent view and animate accordingly to that. I tried from this answer. I think it returns 0.dp to me. So what is the proper way of measuring the item?

Actually I want to animate a view, but my view is 0.dp when I run the application.

@Preview(showBackground = true)
@Composable
fun MoveText() {
    val density = LocalDensity.current
    var columnHeightDp by remember {
        mutableStateOf(0.dp)
    }
    var visible by remember { mutableStateOf(true) }
    val iconOffsetAnimation: Dp by animateDpAsState(
        if (visible) 13.dp else 0.dp, tween(1000)
    )
    val textOffsetAnimation: Dp by animateDpAsState(
        if (visible) 6.dp else 0.dp, tween(1000)
    )
    val viewAlpha: Float by animateFloatAsState(
        targetValue = if (visible) 1f else 0f, animationSpec = tween(
            durationMillis = 1000,
        )
    )
    val heightInDp: Dp by animateDpAsState(
        targetValue = if (visible) {
            columnHeightDp
        } else {
            0.dp
        }, animationSpec = tween(
            durationMillis = 1000,
        )
    )
    ScrollComposeTheme {
        Column(
            modifier = Modifier
                .fillMaxWidth()
                .padding(start = 16.dp, top = 16.dp)
        ) {
            Column(modifier = Modifier
                .onGloballyPositioned { coordinates ->
                    with(density) {
                        columnHeightDp = coordinates.size.height.toDp()
                    }
                }
                .height(heightInDp)
                .background(Color.LightGray)) {
                Image(
                    modifier = Modifier.padding(top = iconOffsetAnimation),
                    alpha = viewAlpha,
                    imageVector = Icons.Default.ShoppingCart,
                    contentDescription = null,
                )
                Text(
                    modifier = Modifier.padding(top = textOffsetAnimation),
                    text = "Hello, Anna",
                    fontSize = 20.sp,
                    color = Color.Black.copy(alpha = viewAlpha),
                )
            }
            Button(
                modifier = Modifier.padding(top = 10.dp),
                onClick = {
                    visible = !visible
                },
            ) {
                Text(text = "Move Text")
            }
        }
    }
}

Actual Output

enter image description here

Expected Output

enter image description here

1

There are 1 best solutions below

5
On BEST ANSWER

I tried to achieve something like this demo video from your question.

 val modifier: Modifier = Modifier.background(Color.LightGray)      
 Column(modifier = if (columnHeightDp != 0.dp) {
                modifier
                    .height(heightInDp)
            } else {
                modifier.onSizeChanged {
                    with(density) {
                        columnHeightDp = it.height.toDp()
                    }
                }.wrapContentHeight()
            },
        ) {
         // your content goes here...Image and Text
           }

Let me explain how i reach to this.

modifier = modifier.onSizeChanged {
                with(density) {
                    columnHeightDp = it.height.toDp()
                }
            }.wrapContentHeight(),

Here for the dynamic height calculation onSizeChanged method works well. So i save this in a variable as per your need. The wrapContentHeight method in modifier is equivalent as WRAP_CONTENT in xml. It will work nicely showing both components (Image and Text)(Button). But we need the animation so what we need to do is.

if (columnHeightDp != 0.dp) {
                modifier
                    .height(heightInDp)
            }

This will apply the animation for the entire Column for Image and Text