aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Kulikov <andreykulikov@google.com>2023-12-22 13:50:31 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-01-04 17:00:13 +0000
commita6953e685381c9c465231bab09ae61785f8c68d7 (patch)
treef4fb05e9a12d518e80f369672b21c0d1d58df663
parent4d0fc064e25e5a42e1b0cbe5687bf7dfdb7759f7 (diff)
downloadsupport-a6953e685381c9c465231bab09ae61785f8c68d7.tar.gz
Make sure we do not remeasure deactivated nodes
Even when it is requested via Remeasurement.forceRemeasure(). Deactivated nodes are always skipped during the regular measure pass, so here it should be a no-op. For fully detached nodes it is a no-op as well. Bug: 316683578 Test: new test in LazyColumnTest (cherry picked from https://android-review.googlesource.com/q/commit:0523a3b7d3ae78829baf54b2abf3bc5dcfc6b6d7) (cherry picked from https://android-review.googlesource.com/q/commit:8d96772b6e40472b701ead5bce6f62498c44b22c) Merged-In: Ic017fdca075806236b071f58bb48095e951126c0 Change-Id: Ic017fdca075806236b071f58bb48095e951126c0
-rw-r--r--compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/lazy/list/LazyColumnTest.kt39
-rw-r--r--compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt5
2 files changed, 44 insertions, 0 deletions
diff --git a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/lazy/list/LazyColumnTest.kt b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/lazy/list/LazyColumnTest.kt
index 51e78852008..3dadcfb163a 100644
--- a/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/lazy/list/LazyColumnTest.kt
+++ b/compose/foundation/foundation/src/androidInstrumentedTest/kotlin/androidx/compose/foundation/lazy/list/LazyColumnTest.kt
@@ -50,6 +50,9 @@ import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.LookaheadScope
+import androidx.compose.ui.layout.SubcomposeLayout
+import androidx.compose.ui.layout.SubcomposeLayoutState
+import androidx.compose.ui.layout.SubcomposeSlotReusePolicy
import androidx.compose.ui.layout.layout
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.assertIsDisplayed
@@ -620,6 +623,42 @@ class LazyColumnTest(val useLookaheadScope: Boolean) {
}
}
+ @Test
+ fun scrollingDeactivatedListIsNotCrashing() {
+ val itemSize = 10f
+ val itemSizeDp = with(rule.density) { itemSize.toDp() }
+
+ val subcomposeState = SubcomposeLayoutState(SubcomposeSlotReusePolicy(1))
+ val state = LazyListState()
+ var compose by mutableStateOf(true)
+ rule.setContent {
+ SubcomposeLayout(state = subcomposeState) { constraints ->
+ val node = if (compose) {
+ subcompose(Unit) {
+ LazyColumn(Modifier.size(itemSizeDp), state) {
+ items(100) {
+ Box(Modifier.size(itemSizeDp))
+ }
+ }
+ }.first().measure(constraints)
+ } else {
+ null
+ }
+ layout(10, 10) {
+ node?.place(0, 0)
+ }
+ }
+ }
+ rule.runOnIdle {
+ compose = false
+ }
+ rule.runOnIdle {
+ runBlocking {
+ state.scrollBy(itemSize)
+ }
+ }
+ }
+
@Composable
private fun LazyRowWrapped(content: @Composable () -> Unit) {
LazyRow {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt
index a9b4673b97b..6f434972728 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/node/MeasureAndLayoutDelegate.kt
@@ -425,6 +425,11 @@ internal class MeasureAndLayoutDelegate(private val root: LayoutNode) {
}
fun measureAndLayout(layoutNode: LayoutNode, constraints: Constraints) {
+ if (layoutNode.isDeactivated) {
+ // regular measureAndLayout() pass will skip deactivated nodes, so here we should
+ // do nothing as well.
+ return
+ }
require(layoutNode != root) { "measureAndLayout called on root" }
performMeasureAndLayout {
relayoutNodes.remove(layoutNode)