Issue
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.
Solution
Short answer, yes. Composables enter and exit composition based on on UI structure 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 condition is 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()
}
}
}
Even if a Composable 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()
}
}
}
Composables don't 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 counter is 3 stay in composition while and exits when condition is not met anymore.
Answered By - Thracian
Answer Checked By - Marie Seifert (JavaFixing Admin)