19

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?

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
user3872620
  • 1,036
  • 10
  • 12

3 Answers3

36

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    
}
Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
3

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.

Thracian
  • 43,021
  • 16
  • 133
  • 222
1

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

@Composable
fun Sample() {
    Text(
        "Hello",
        Modifier.onSizeChanged {
            println("Width of Text in dp: ${it.width.toDp}")
            println("Height of Text in dp: ${it.height.toDp}")
        }
    )
}

val Int.toDp get() = (this / Resources.getSystem().displayMetrics.density).toInt()
Tatsuya Fujisaki
  • 1,434
  • 15
  • 18