What's the correct way to invalidate draw for `Lay...
# compose
k
What's the correct way to invalidate draw for
LayoutModifierNode
+
DrawModifierNode
+
placeable.placeWithLayer
? It only works with
node.invalidateDrawForSubtree()
, and
node.invalidateDraw()
doesn't work.
Copy code
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.GraphicsLayerScope
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.MeasureResult
import androidx.compose.ui.layout.MeasureScope
import androidx.compose.ui.node.DrawModifierNode
import androidx.compose.ui.node.LayoutModifierNode
import androidx.compose.ui.node.ModifierNodeElement
import androidx.compose.ui.node.invalidateDraw
import androidx.compose.ui.node.updateLayerBlock
import androidx.compose.ui.platform.InspectorInfo
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntOffset

fun Modifier.fillClip(
    color: Color,
    shape: Shape,
    blendMode: BlendMode = BlendMode.SrcOver
) = this then FillClipElement(color, shape, blendMode)

private data class FillClipElement(
    val color: Color,
    val shape: Shape,
    val blendMode: BlendMode
) : ModifierNodeElement<FillClipNode>() {

    override fun create(): FillClipNode = FillClipNode(color, shape, blendMode)

    override fun update(node: FillClipNode) {
        node.color = color
        node.shape = shape
        node.blendMode = blendMode
        node.invalidateLayerBlock()
        node.invalidateDraw()
    }

    override fun InspectorInfo.inspectableProperties() {
        name = "fillClip"
        properties["color"] = color
        properties["shape"] = shape
        properties["blendMode"] = blendMode
    }
}

private class FillClipNode(
    var color: Color,
    var shape: Shape,
    var blendMode: BlendMode
) : LayoutModifierNode, DrawModifierNode, Modifier.Node() {

    override val shouldAutoInvalidate: Boolean = false

    private val layerBlock: GraphicsLayerScope.() -> Unit = {
        clip = true
        shape = this@FillClipNode.shape
    }

    override fun MeasureScope.measure(
        measurable: Measurable,
        constraints: Constraints,
    ): MeasureResult {
        val placeable = measurable.measure(constraints)
        return layout(placeable.width, placeable.height) {
            placeable.placeWithLayer(IntOffset.Zero, layerBlock = layerBlock)
        }
    }

    override fun ContentDrawScope.draw() {
        drawRect(color, blendMode = blendMode)
        drawContent()
    }

    fun invalidateLayerBlock() {
        updateLayerBlock(layerBlock)
    }
}
l
I think invalidating placement should work in this case
But
updateLayerBlock
should work, you just need to use a mutable variable and assign a new lambda I think?