Does a composable of size 0dp even get composed or recomposed or is it just ignored by jetpack compose at runtime? This is to know if performance wise, hiding a composable using an if statement is the same as setting its size to 0dp.
CodePudding user response:
Short answer, yes. They enter and exit composition based on on your UI structure but not size modifier, Under the hood of Jetpack Compose — part 2 of 2 article explains this very well. Conditional Composable blocks enter composition when the conditions are met and stay in composition, or recomposed if the state they read changes then exit composition when it's no longer valid. You can check this answer for conditional composition.
For example you can set in example below that Composable is laid out and drawn even if it has 0.dp size
@Composable
private fun CompositionSample() {
val context = LocalContext.current
Box(
Modifier
.size(0.dp)
.layout { measurable, constraints ->
val placeable = measurable.measure(constraints)
Toast
.makeText(
context,
"Layout Phase width: ${placeable.width}, height: ${placeable.height}",
Toast.LENGTH_SHORT
)
.show()
layout(placeable.width, placeable.height) {
placeable.placeRelative(0, 0)
}
}
.drawWithContent {
Toast
.makeText(context, "Draw Phase $size", Toast.LENGTH_SHORT)
.show()
drawContent()
}
) {
Toast.makeText(context, "BoxScope", Toast.LENGTH_SHORT).show()
Column {
Toast.makeText(context, "ColumnScope", Toast.LENGTH_SHORT).show()
}
}
}
Also even if item is not visible on screen yet because of verticalScroll() or horizontalScroll() modifiers it enters composition. That's why LazyLists which subcomposes items on screen only to be more performant against scroll modifiers.
@Composable
private fun HorizontalComposableSample() {
val context = LocalContext.current
Row(
Modifier
.fillMaxWidth()
.horizontalScroll(rememberScrollState())
){
Box(
Modifier
.size(1000.dp, 200.dp)
.background(Color.Red))
Column(modifier= Modifier
.size(200.dp)
.background(Color.Green)) {
Toast.makeText(context, "ColumnScope", Toast.LENGTH_SHORT).show()
}
}
}
And your Composable's don't even have to be a UI composable either to enter or exit composition.
@Composable
private fun NonUIComposableSample() {
val context = LocalContext.current
var counter by remember { mutableStateOf(0) }
var color by remember { mutableStateOf(Color.Red) }
if (counter in 3..5) {
DisposableEffect(Unit) {
Toast.makeText(context, "Entering Composition counter: $counter", Toast.LENGTH_SHORT).show()
color = Color.Yellow
onDispose {
color = Color.Green
Toast.makeText(context, "Exiting Composition counter: $counter", Toast.LENGTH_SHORT).show()
}
}
}
Button(onClick = { counter }) {
Text("Counter: $counter", color = color)
}
}
In this example Block with DisposableEffect enters composition when modulus of 3 stay in composition while and exits when conditions are not met.