android-jetpack-composekotlin-multiplatformcompose-multiplatform

fillMaxSize() after rotate() leads to wrong results


The following code gives me output I did not expect.

@Composable
fun App() {
    MaterialTheme {
        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(Color.Gray)
            ,
        ) {
            Image(
                modifier = Modifier
                    .rotate(90f)
                    .fillMaxSize()
                ,
                painter = painterResource(Res.drawable.hello),
                contentDescription = null,
            )
        }
    }
}

The image is rotated but it does not fill the size of its parent. Instead I would expect the image to fill one or two dimensions of the parent, like illustrated on the right.

Actual result vs. Expected result:

I have tried to set the contentScale to ContentScale.Crop but that results in even worse output:

Crop variant


Solution

  • This isn't about the order of the modifiers, it's how the rotate() modifier works in Compose. It doesn’t change the measured size of the composable, so fillMaxSize() is computed before the rotation. That's why, after a 90° turn, your image doesn't cover the parent. Think of it like the pixels are rotating, not the layout itself.

    There are multiple approaches you can use to counter this though. One solution is to wrap it in a BoxWithConstraints and then swap the measured constraints in order to get the desired effect:

    @Composable
    fun App() {
        MaterialTheme {
            Box(
                modifier = Modifier
                    .fillMaxSize()
                    .background(Color.Gray),
            ) {
                BoxWithConstraints(
                    modifier = Modifier.fillMaxSize(),
                    contentAlignment = Alignment.Center,
                ) {
                    Image(
                        modifier = Modifier
                            .requiredHeight(maxWidth) // Swap width and height
                            .requiredWidth(maxHeight)
                            .rotate(90f),
                        painter = painterResource(R.drawable.hello),
                        contentDescription = null,
                    )
                }
            }
        }
    }
    

    And here's the result: