aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Mount <mount@google.com>2019-06-20 08:59:16 -0700
committerGeorge Mount <mount@google.com>2019-06-24 14:35:24 -0700
commit8f9f6d27cc256792327afc0fc32b5e54b898834c (patch)
tree3a99f54aabc5ff7183d2a95e266ae13dd20b241c
parent1457ddc0d36da418a7a11badf6da252f966deae6 (diff)
downloadsupport-8f9f6d27cc256792327afc0fc32b5e54b898834c.tar.gz
Fix: adding elements didn't cause remeasure.
Fixes: 135668890 When a new element was added through composition, the containing layout didn't remeasure and relayout that child. This CL asks the parent to remeasure and relayout when a child is added or removed. Test: new test Change-Id: Ida8f71f9f6a159be79767c04b96ffc1d2c42b3fe
-rw-r--r--ui/framework/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt50
-rw-r--r--ui/platform/api/1.0.0-alpha01.txt1
-rw-r--r--ui/platform/api/current.txt1
-rw-r--r--ui/platform/src/main/java/androidx/ui/core/AndroidOwner.kt25
-rw-r--r--ui/platform/src/main/java/androidx/ui/core/ComponentNodes.kt18
5 files changed, 79 insertions, 16 deletions
diff --git a/ui/framework/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt b/ui/framework/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt
index 52cf3dc761a..3d4ff9abfbe 100644
--- a/ui/framework/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt
+++ b/ui/framework/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt
@@ -665,6 +665,51 @@ class AndroidLayoutDrawTest {
}
}
+ // When a new child is added, the parent must be remeasured because we don't know
+ // if it affects the size and the child's measure() must be called as well.
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+ @Test
+ fun testRelayoutOnNewChild() {
+ val drawChild = DoDraw()
+
+ val outerColor = Color(0xFF000080.toInt())
+ val innerColor = Color(0xFFFFFFFF.toInt())
+ runOnUiThread {
+ activity.setContent {
+ CraneWrapper {
+ AtLeastSize(size = 30.ipx) {
+ Draw { canvas, parentSize ->
+ drawLatch.countDown()
+ val paint = Paint()
+ paint.color = outerColor
+ canvas.drawRect(parentSize.toRect(), paint)
+ }
+ if (drawChild.value) {
+ Padding(size = 20.ipx) {
+ AtLeastSize(size = 20.ipx) {
+ Draw { canvas, parentSize ->
+ drawLatch.countDown()
+ val paint = Paint()
+ paint.color = innerColor
+ canvas.drawRect(parentSize.toRect(), paint)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // The padded area doesn't draw
+ validateSquareColors(outerColor = outerColor, innerColor = outerColor, size = 10)
+
+ drawLatch = CountDownLatch(1)
+ runOnUiThread { drawChild.value = true }
+
+ validateSquareColors(outerColor = outerColor, innerColor = innerColor, size = 20)
+ }
+
// We only need this because IR compiler doesn't like converting lambdas to Runnables
private fun runOnUiThread(block: () -> Unit) {
val runnable: Runnable = object : Runnable {
@@ -1044,4 +1089,7 @@ class SquareModel(
)
@Model
-class OffsetModel(var offset: IntPx) \ No newline at end of file
+class OffsetModel(var offset: IntPx)
+
+@Model
+class DoDraw(var value: Boolean = false)
diff --git a/ui/platform/api/1.0.0-alpha01.txt b/ui/platform/api/1.0.0-alpha01.txt
index 579dd35cc91..24d3185a20c 100644
--- a/ui/platform/api/1.0.0-alpha01.txt
+++ b/ui/platform/api/1.0.0-alpha01.txt
@@ -21,7 +21,6 @@ package androidx.ui.core {
method public void onSizeChange(androidx.ui.core.LayoutNode layoutNode);
method public void onStartLayout(androidx.ui.core.LayoutNode layoutNode);
method public void onStartMeasure(androidx.ui.core.LayoutNode layoutNode);
- method public void requestRelayout(androidx.ui.core.LayoutNode layoutNode);
method public void sendEvent(android.view.MotionEvent event);
method public void setCommitUnsubscribe(kotlin.jvm.functions.Function0<kotlin.Unit>? p);
method public void setConstraints(androidx.ui.core.Constraints p);
diff --git a/ui/platform/api/current.txt b/ui/platform/api/current.txt
index 579dd35cc91..24d3185a20c 100644
--- a/ui/platform/api/current.txt
+++ b/ui/platform/api/current.txt
@@ -21,7 +21,6 @@ package androidx.ui.core {
method public void onSizeChange(androidx.ui.core.LayoutNode layoutNode);
method public void onStartLayout(androidx.ui.core.LayoutNode layoutNode);
method public void onStartMeasure(androidx.ui.core.LayoutNode layoutNode);
- method public void requestRelayout(androidx.ui.core.LayoutNode layoutNode);
method public void sendEvent(android.view.MotionEvent event);
method public void setCommitUnsubscribe(kotlin.jvm.functions.Function0<kotlin.Unit>? p);
method public void setConstraints(androidx.ui.core.Constraints p);
diff --git a/ui/platform/src/main/java/androidx/ui/core/AndroidOwner.kt b/ui/platform/src/main/java/androidx/ui/core/AndroidOwner.kt
index d042f491d72..1ffe8c11daf 100644
--- a/ui/platform/src/main/java/androidx/ui/core/AndroidOwner.kt
+++ b/ui/platform/src/main/java/androidx/ui/core/AndroidOwner.kt
@@ -198,11 +198,20 @@ class AndroidCraneView constructor(context: Context)
override fun onRequestMeasure(layoutNode: LayoutNode) {
// find root of layout request:
+ if (layoutNode.needsRemeasure) {
+ // don't need to do anything because it already needs to be remeasured
+ return
+ }
layoutNode.needsRemeasure = true
var layout = layoutNode
- while (layout.parentLayoutNode != null && layout.affectsParentSize) {
+ while (layout.parentLayoutNode != null && layout.parentLayoutNode != root &&
+ layout.affectsParentSize) {
layout = layout.parentLayoutNode!!
+ if (layout.needsRemeasure) {
+ // don't need to do anything else since the parent already needs measuring
+ return
+ }
layout.needsRemeasure = true
}
@@ -214,8 +223,8 @@ class AndroidCraneView constructor(context: Context)
}
}
- fun requestRelayout(layoutNode: LayoutNode) {
- if (layoutNode == root) {
+ private fun requestRelayout(layoutNode: LayoutNode) {
+ if (layoutNode == root || constraints.isZero) {
requestLayout()
} else if (relayoutNodes.isEmpty()) {
Choreographer.getInstance().postFrameCallback {
@@ -259,13 +268,11 @@ class AndroidCraneView constructor(context: Context)
relayoutNodes.sortedBy { it.depth }.forEach { layoutNode ->
if (layoutNode.needsRemeasure) {
val parent = layoutNode.parentLayoutNode
- if (parent != null) {
+ if (parent != null && parent.layout != null) {
// This should call measure and layout on the child
- val parentLayout = parent.layout
- if (parentLayout != null) {
- parent.needsRelayout = true
- parentLayout.callLayout()
- }
+ val parentLayout = parent.layout!!
+ parent.needsRelayout = true
+ parentLayout.callLayout()
} else {
layoutNode.layout?.callMeasure(layoutNode.constraints)
layoutNode.layout?.callLayout()
diff --git a/ui/platform/src/main/java/androidx/ui/core/ComponentNodes.kt b/ui/platform/src/main/java/androidx/ui/core/ComponentNodes.kt
index 04e4607ba29..72ba120ab28 100644
--- a/ui/platform/src/main/java/androidx/ui/core/ComponentNodes.kt
+++ b/ui/platform/src/main/java/androidx/ui/core/ComponentNodes.kt
@@ -394,7 +394,7 @@ class LayoutNode : ComponentNode() {
/**
* `true` when the parent's size depends on this LayoutNode's size
*/
- var affectsParentSize: Boolean = false
+ var affectsParentSize: Boolean = true
/**
* `true` when called between [startMeasure] and [endMeasure]
@@ -405,14 +405,14 @@ class LayoutNode : ComponentNode() {
* `true` when the layout has been dirtied by [requestRemeasure]. `false` after
* the measurement has been complete ([resize] has been called).
*/
- var needsRemeasure = true
+ var needsRemeasure = false
internal set
/**
* `true` when the layout has been measured or dirtied because the layout
* lambda accessed a model that has been dirtied.
*/
- var needsRelayout = true
+ var needsRelayout = false
internal set
override val parentLayoutNode: LayoutNode?
@@ -421,6 +421,16 @@ class LayoutNode : ComponentNode() {
override val containingLayoutNode: LayoutNode?
get() = this
+ override fun attach(owner: Owner) {
+ super.attach(owner)
+ requestRemeasure()
+ }
+
+ override fun detach() {
+ parentLayoutNode?.requestRemeasure()
+ super.detach()
+ }
+
fun moveTo(x: IntPx, y: IntPx) {
visible = true
if (x != this.x || y != this.y) {
@@ -432,7 +442,6 @@ class LayoutNode : ComponentNode() {
fun resize(width: IntPx, height: IntPx) {
val parent = parentLayoutNode
- needsRemeasure = false // we must have just finished measurement
if (parent != null && parent.isInMeasure) {
affectsParentSize = true
}
@@ -461,6 +470,7 @@ class LayoutNode : ComponentNode() {
fun endMeasure() {
owner?.onEndMeasure(this)
isInMeasure = false
+ needsRemeasure = false
needsRelayout = true
}