compose-multiplatform

How to get screen width and height in Compose Multiplatform?


How can I get the screen size in Compose Multiplatform without using expect/actual?

I have found the following explanation in https://github.com/JetBrains/compose-multiplatform/discussions/3225#discussioncomment-7195192:

You can also use a Layout as your root Composable and obtain the size from the passed constraints. This solution doesn't depend on platform implementations and also gives you the exact size given to your Composable which could be different from the device screen size in some cases.

Once you have that size can use a CompositionLocal to pass it down the composable tree

I have not been able to fully understand or successfully implement the suggested layout.


Solution

  • I got the answer at https://github.com/JetBrains/compose-multiplatform/discussions/3225#discussioncomment-7386013 🙌

    Using that I've created a small example that might be helpful for others looking for the answer:

    import androidx.compose.foundation.layout.Box
    import androidx.compose.foundation.layout.fillMaxSize
    import androidx.compose.material.Text
    import androidx.compose.runtime.Composable
    import androidx.compose.runtime.mutableStateOf
    import androidx.compose.runtime.remember
    import androidx.compose.ui.Alignment
    import androidx.compose.ui.Modifier
    import androidx.compose.ui.layout.Layout
    
    @Composable
    fun App() {
        val screenSize = remember { mutableStateOf(Pair(-1, -1)) }
        Layout(
            content = {
                Box(modifier = Modifier.fillMaxSize()) {
                    Text("Screen size: ${screenSize.value.first}x${screenSize.value.second}px", modifier = Modifier.align(Alignment.Center))
                }
            },
            measurePolicy = { measurables, constraints ->
                // Use the max width and height from the constraints
                val width = constraints.maxWidth
                val height = constraints.maxHeight
    
                screenSize.value = Pair(width, height)
                println("Width: $width, height: $height")
    
                // Measure and place children composables
                val placeables = measurables.map { measurable ->
                    measurable.measure(constraints)
                }
    
                layout(width, height) {
                    var yPosition = 0
                    placeables.forEach { placeable ->
                        placeable.placeRelative(x = 0, y = yPosition)
                        yPosition += placeable.height
                    }
                }
            }
        )
    }
    

    Here's a screenshot of the code running on macOS, iOS simulator and Android emulator: enter image description here