Skip to content

Track placement order (and non-placement) and honor it in draw #720

Open
@mattprecious

Description

@mattprecious

If in a custom Layout implementation, a node gets measured/placed during one composition and then not measured/placed on a subsequent one, it still participates in draw.

@Test
fun conditionalPlacement() = runTest {
  runMosaicTest {
    setContent {
      Layout(
        modifier = Modifier.width(LocalTerminal.current.size.width),
        content = {
          Text("Hello")
          Text("World")
        }
      ) { measurables, constraints ->
        val helloPlaceable = measurables[0].measure(constraints)
        val worldPlaceable = if (constraints.maxWidth >= 10) {
          measurables[1].measure(constraints)
        } else {
          null
        }

        layout(5, 1) {
          helloPlaceable.place(0, 0)
          worldPlaceable?.place(0, 0)
        }
      }
    }

    assertThat(awaitSnapshot()).isEqualTo("World")

    terminalState.update { copy(size = IntSize(5, 1)) }

    assertThat(awaitSnapshot()).isEqualTo("Hello")
  }
}

Not entirely sure if this is allowed per the Layout contract? I don't believe this is the current behavior of Compose UI. My test:

@Preview
@Composable
fun ConditionalPlacementTest() {
  var redSize by remember { mutableStateOf(100.dp) }

  LaunchedEffect(Unit) {
    while (true) {
      delay(3000)
      redSize = if (redSize == 100.dp) 300.dp else 100.dp
    }
  }

  Layout(
    content = {
      Box(modifier = Modifier.size(redSize).background(Color.Red))
      Box(modifier = Modifier.size(100.dp).background(Color.Green))
    }
  ) { measurables, constraints ->
    val redPlaceable = measurables[0].measure(constraints)
    val greenPlaceable = if (redPlaceable.width < 300) {
      measurables[1].measure(constraints)
    } else {
      null
    }

    layout(redPlaceable.width, redPlaceable.height) {
      redPlaceable.place(0, 0)
      greenPlaceable?.place(0, 0)
    }
  }
}

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions