user3872620
user3872620

Reputation: 1554

How to get the size of a Composable during runtime?

I have as an example the following Composable:

@Composable
fun CustomCanvas(
) {
   Box(
      Modifier
        .aspectRatio(1.33f)
        .fillMaxWidth())
} 

How do I know the size of this object after composition?

Why I want to know: I'm trying to resize and place images on a canvas. This requires knowing the size of the canvas. And no, I don't want to hardcode the size of the canvas. How to do this?

Upvotes: 25

Views: 17803

Answers (4)

vidalbenjoe
vidalbenjoe

Reputation: 975

To get the actual size of the composable, you can use the LayoutCoordinates. Please see below:

   var columnHeight by remember { mutableStateOf(0.dp) }

   Column(modifier = Modifier
    .onGloballyPositioned { layoutCoordinates: LayoutCoordinates ->
            with(density) {
                 columnHeight = layoutCoordinates.size.height.toDp()
            }
        }

Upvotes: 0

Tatsuya Fujisaki
Tatsuya Fujisaki

Reputation: 1969

You can use Modifier.onSizeChanged to find out the size of a composable at runtime.

@Preview
@Composable
fun Example() {
    Text(
        text = "Hello",
        modifier = Modifier.onSizeChanged {
            println("Text size: $it[dp]") // Text size: 87 x 45[dp]
            println("Text width: ${it.width.dp}") // Text width: 87.0.dp
            println("Text height: ${it.height.dp}") // Text height: 45.0.dp
        }
    )
}

Upvotes: 4

Thracian
Thracian

Reputation: 66516

You can do this several ways. BoxWithConstraints does not always return correct size because as the name describes it returns Constraints. Max width or height of Constraints doesn't always match width or height of your Composable.

Using Modifier.onSizeChanged{size:IntSize} or Modifier.onGloballyPositioned{} with a mutableState causes another recomposition which might cause change in UI on next frame.

You can check this answer out how to get exact size without recomposition and exact size on every occasion.

Upvotes: 5

Gabriele Mariotti
Gabriele Mariotti

Reputation: 363439

You can use the onGloballyPositioned modifier:

var size by remember { mutableStateOf(IntSize.Zero) }

Box(Modifier.onGloballyPositioned { coordinates ->
    size = coordinates.size
}) {
   //...
}

Also the Canvas has a DrawScope which has the size property.

Canvas() {
    val canvasSize = size    
}

Upvotes: 40

Related Questions