Use own cache drawing to prevent delegating
This commit is contained in:
1 parent
71fe874b4e
commit
5953764cbb
8 files changed
+160
-66
No files matched your search
@@ -8,9 +8,9 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.draw.CacheDrawScope
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import androidx.compose.ui.unit.Density
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
|
||||
@@ -43,7 +43,7 @@ internal abstract class BackdropEffectScopeImpl : BackdropEffectScope {
|
||||
return runtimeShaders.getOrPut(key) { RuntimeShader(string) }
|
||||
}
|
||||
|
||||
fun applyDrawScope(scope: CacheDrawScope) {
|
||||
fun applyDrawScope(scope: DrawScope) {
|
||||
density = scope.density
|
||||
fontScale = scope.fontScale
|
||||
size = scope.size
|
||||
|
||||
@@ -2,19 +2,22 @@ package com.kyant.backdrop
|
||||
|
||||
import android.os.Build
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.CacheDrawModifierNode
|
||||
import androidx.compose.ui.graphics.GraphicsLayerScope
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.graphics.asComposeRenderEffect
|
||||
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import androidx.compose.ui.graphics.layer.GraphicsLayer
|
||||
import androidx.compose.ui.graphics.layer.drawLayer
|
||||
import androidx.compose.ui.layout.Measurable
|
||||
import androidx.compose.ui.layout.MeasureResult
|
||||
import androidx.compose.ui.layout.MeasureScope
|
||||
import androidx.compose.ui.node.DelegatingNode
|
||||
import androidx.compose.ui.node.DrawModifierNode
|
||||
import androidx.compose.ui.node.LayoutModifierNode
|
||||
import androidx.compose.ui.node.ModifierNodeElement
|
||||
import androidx.compose.ui.node.ObserverModifierNode
|
||||
import androidx.compose.ui.node.invalidateDraw
|
||||
import androidx.compose.ui.node.observeReads
|
||||
import androidx.compose.ui.node.requireGraphicsContext
|
||||
import androidx.compose.ui.platform.InspectorInfo
|
||||
import androidx.compose.ui.unit.Constraints
|
||||
@@ -85,7 +88,7 @@ private class ContentBackdropElement(
|
||||
node.onDrawBehind = onDrawBehind
|
||||
node.onDrawSurface = onDrawSurface
|
||||
node.effects = effects
|
||||
node.drawNode.invalidateDrawCache()
|
||||
node.invalidateDrawCache()
|
||||
}
|
||||
|
||||
override fun InspectorInfo.inspectableProperties() {
|
||||
@@ -122,7 +125,7 @@ private class ContentBackdropNode(
|
||||
var onDrawBehind: (DrawScope.() -> Unit)?,
|
||||
var onDrawSurface: (DrawScope.() -> Unit)?,
|
||||
var effects: BackdropEffectScope.() -> Unit
|
||||
) : LayoutModifierNode, DelegatingNode() {
|
||||
) : LayoutModifierNode, DrawModifierNode, ObserverModifierNode, Modifier.Node() {
|
||||
|
||||
override val shouldAutoInvalidate: Boolean = false
|
||||
|
||||
@@ -138,22 +141,14 @@ private class ContentBackdropNode(
|
||||
null
|
||||
}
|
||||
|
||||
val drawNode = delegate(CacheDrawModifierNode {
|
||||
private var isCacheValid = false
|
||||
private val cacheDrawBlock: DrawScope.() -> Unit = {
|
||||
if (effectScope != null) {
|
||||
effectScope.applyDrawScope(this)
|
||||
effects(effectScope)
|
||||
graphicsLayer?.renderEffect = effectScope.renderEffect?.asComposeRenderEffect()
|
||||
}
|
||||
|
||||
onDrawWithContent {
|
||||
onDrawBehind?.invoke(this)
|
||||
graphicsLayer?.let { layer ->
|
||||
layer.record { this@onDrawWithContent.drawContent() }
|
||||
drawLayer(layer)
|
||||
}
|
||||
onDrawSurface?.invoke(this)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private val layerBlock: GraphicsLayerScope.() -> Unit = {
|
||||
clip = true
|
||||
@@ -171,6 +166,31 @@ private class ContentBackdropNode(
|
||||
}
|
||||
}
|
||||
|
||||
override fun ContentDrawScope.draw() {
|
||||
if (!isCacheValid) {
|
||||
observeReads { cacheDrawBlock() }
|
||||
isCacheValid = true
|
||||
}
|
||||
|
||||
onDrawBehind?.invoke(this)
|
||||
|
||||
graphicsLayer?.let { layer ->
|
||||
layer.record { this@draw.drawContent() }
|
||||
drawLayer(layer)
|
||||
}
|
||||
|
||||
onDrawSurface?.invoke(this)
|
||||
}
|
||||
|
||||
override fun onObservedReadsChanged() {
|
||||
invalidateDrawCache()
|
||||
}
|
||||
|
||||
fun invalidateDrawCache() {
|
||||
isCacheValid = false
|
||||
invalidateDraw()
|
||||
}
|
||||
|
||||
override fun onAttach() {
|
||||
val graphicsContext = requireGraphicsContext()
|
||||
graphicsLayer = graphicsContext.createGraphicsLayer()
|
||||
|
||||
@@ -5,10 +5,10 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.CacheDrawModifierNode
|
||||
import androidx.compose.ui.graphics.GraphicsLayerScope
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.graphics.asComposeRenderEffect
|
||||
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import androidx.compose.ui.graphics.layer.GraphicsLayer
|
||||
import androidx.compose.ui.graphics.layer.drawLayer
|
||||
@@ -16,10 +16,13 @@ import androidx.compose.ui.layout.LayoutCoordinates
|
||||
import androidx.compose.ui.layout.Measurable
|
||||
import androidx.compose.ui.layout.MeasureResult
|
||||
import androidx.compose.ui.layout.MeasureScope
|
||||
import androidx.compose.ui.node.DelegatingNode
|
||||
import androidx.compose.ui.node.DrawModifierNode
|
||||
import androidx.compose.ui.node.GlobalPositionAwareModifierNode
|
||||
import androidx.compose.ui.node.LayoutModifierNode
|
||||
import androidx.compose.ui.node.ModifierNodeElement
|
||||
import androidx.compose.ui.node.ObserverModifierNode
|
||||
import androidx.compose.ui.node.invalidateDraw
|
||||
import androidx.compose.ui.node.observeReads
|
||||
import androidx.compose.ui.node.requireGraphicsContext
|
||||
import androidx.compose.ui.platform.InspectorInfo
|
||||
import androidx.compose.ui.unit.Constraints
|
||||
@@ -104,7 +107,7 @@ private class DrawBackdropElement(
|
||||
node.onDrawBackdrop = onDrawBackdrop
|
||||
node.onDrawSurface = onDrawSurface
|
||||
node.effects = effects
|
||||
node.drawNode.invalidateDrawCache()
|
||||
node.invalidateDrawCache()
|
||||
}
|
||||
|
||||
override fun InspectorInfo.inspectableProperties() {
|
||||
@@ -149,7 +152,7 @@ private class DrawBackdropNode(
|
||||
var onDrawBackdrop: DrawScope.(drawBackdrop: DrawScope.() -> Unit) -> Unit,
|
||||
var onDrawSurface: (DrawScope.() -> Unit)?,
|
||||
var effects: BackdropEffectScope.() -> Unit
|
||||
) : LayoutModifierNode, GlobalPositionAwareModifierNode, DelegatingNode() {
|
||||
) : LayoutModifierNode, DrawModifierNode, GlobalPositionAwareModifierNode, ObserverModifierNode, Modifier.Node() {
|
||||
|
||||
override val shouldAutoInvalidate: Boolean = false
|
||||
|
||||
@@ -166,28 +169,14 @@ private class DrawBackdropNode(
|
||||
null
|
||||
}
|
||||
|
||||
val drawNode = delegate(CacheDrawModifierNode {
|
||||
private var isCacheValid = false
|
||||
private val cacheDrawBlock: DrawScope.() -> Unit = {
|
||||
if (effectScope != null) {
|
||||
effectScope.applyDrawScope(this)
|
||||
effects(effectScope)
|
||||
graphicsLayer?.renderEffect = effectScope.renderEffect?.asComposeRenderEffect()
|
||||
}
|
||||
|
||||
onDrawWithContent {
|
||||
onDrawBehind?.invoke(this)
|
||||
|
||||
val layer = graphicsLayer
|
||||
val recordBlock = recordBlock
|
||||
if (layer != null && recordBlock != null) {
|
||||
layer.record(block = recordBlock)
|
||||
drawLayer(layer)
|
||||
}
|
||||
|
||||
onDrawSurface?.invoke(this)
|
||||
|
||||
drawContent()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private val layerBlock: GraphicsLayerScope.() -> Unit = {
|
||||
clip = true
|
||||
@@ -205,12 +194,41 @@ private class DrawBackdropNode(
|
||||
}
|
||||
}
|
||||
|
||||
override fun ContentDrawScope.draw() {
|
||||
if (!isCacheValid) {
|
||||
observeReads { cacheDrawBlock() }
|
||||
isCacheValid = true
|
||||
}
|
||||
|
||||
onDrawBehind?.invoke(this)
|
||||
|
||||
val layer = graphicsLayer
|
||||
val recordBlock = recordBlock
|
||||
if (layer != null && recordBlock != null) {
|
||||
layer.record(block = recordBlock)
|
||||
drawLayer(layer)
|
||||
}
|
||||
|
||||
onDrawSurface?.invoke(this)
|
||||
|
||||
drawContent()
|
||||
}
|
||||
|
||||
override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
|
||||
if (coordinates.isAttached) {
|
||||
recordBlock = { with(backdrop) { onDrawBackdrop { drawBackdrop(coordinates) } } }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onObservedReadsChanged() {
|
||||
invalidateDrawCache()
|
||||
}
|
||||
|
||||
fun invalidateDrawCache() {
|
||||
isCacheValid = false
|
||||
invalidateDraw()
|
||||
}
|
||||
|
||||
override fun onAttach() {
|
||||
val graphicsContext = requireGraphicsContext()
|
||||
graphicsLayer = graphicsContext.createGraphicsLayer()
|
||||
|
||||
@@ -4,12 +4,14 @@ import android.graphics.BlurMaskFilter
|
||||
import android.graphics.Paint
|
||||
import android.graphics.RectF
|
||||
import android.os.Build
|
||||
import androidx.compose.ui.draw.CacheDrawModifierNode
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.GraphicsLayerScope
|
||||
import androidx.compose.ui.graphics.Outline
|
||||
import androidx.compose.ui.graphics.asAndroidPath
|
||||
import androidx.compose.ui.graphics.asComposePaint
|
||||
import androidx.compose.ui.graphics.asComposeRenderEffect
|
||||
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import androidx.compose.ui.graphics.isUnspecified
|
||||
import androidx.compose.ui.graphics.layer.GraphicsLayer
|
||||
import androidx.compose.ui.graphics.layer.drawLayer
|
||||
@@ -18,9 +20,12 @@ import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.layout.Measurable
|
||||
import androidx.compose.ui.layout.MeasureResult
|
||||
import androidx.compose.ui.layout.MeasureScope
|
||||
import androidx.compose.ui.node.DelegatingNode
|
||||
import androidx.compose.ui.node.DrawModifierNode
|
||||
import androidx.compose.ui.node.LayoutModifierNode
|
||||
import androidx.compose.ui.node.ModifierNodeElement
|
||||
import androidx.compose.ui.node.ObserverModifierNode
|
||||
import androidx.compose.ui.node.invalidateDraw
|
||||
import androidx.compose.ui.node.observeReads
|
||||
import androidx.compose.ui.node.requireGraphicsContext
|
||||
import androidx.compose.ui.platform.InspectorInfo
|
||||
import androidx.compose.ui.unit.Constraints
|
||||
@@ -41,7 +46,7 @@ internal class HighlightElement(
|
||||
override fun update(node: HighlightNode) {
|
||||
node.shapeProvider = shapeProvider
|
||||
node.highlight = highlight
|
||||
node.drawNode.invalidateDrawCache()
|
||||
node.invalidateDrawCache()
|
||||
}
|
||||
|
||||
override fun InspectorInfo.inspectableProperties() {
|
||||
@@ -70,7 +75,7 @@ internal class HighlightElement(
|
||||
internal class HighlightNode(
|
||||
var shapeProvider: BackdropShapeProvider,
|
||||
var highlight: () -> Highlight?
|
||||
) : LayoutModifierNode, DelegatingNode() {
|
||||
) : LayoutModifierNode, DrawModifierNode, ObserverModifierNode, Modifier.Node() {
|
||||
|
||||
override val shouldAutoInvalidate: Boolean = false
|
||||
|
||||
@@ -80,13 +85,16 @@ internal class HighlightNode(
|
||||
style = Paint.Style.STROKE
|
||||
}
|
||||
|
||||
val drawNode = delegate(CacheDrawModifierNode {
|
||||
val highlight = highlight()
|
||||
private var isCacheValid = false
|
||||
private var _highlight: Highlight? = null
|
||||
private val cacheDrawBlock: DrawScope.() -> Unit = cacheDrawBlock@{
|
||||
val highlight = highlight().also { _highlight = it }
|
||||
val graphicsLayer = graphicsLayer
|
||||
if (highlight == null || graphicsLayer == null ||
|
||||
highlight.width.value <= 0f || highlight.color.isUnspecified
|
||||
) {
|
||||
return@CacheDrawModifierNode onDrawWithContent { drawContent() }
|
||||
_highlight = null
|
||||
return@cacheDrawBlock
|
||||
}
|
||||
|
||||
val size = size
|
||||
@@ -129,16 +137,7 @@ internal class HighlightNode(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onDrawWithContent {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
graphicsLayer.renderEffect =
|
||||
highlight.style().createRenderEffect(size, strokeWidth)?.asComposeRenderEffect()
|
||||
}
|
||||
drawContent()
|
||||
drawLayer(graphicsLayer)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private val layerBlock: GraphicsLayerScope.() -> Unit = {
|
||||
clip = true
|
||||
@@ -156,6 +155,35 @@ internal class HighlightNode(
|
||||
}
|
||||
}
|
||||
|
||||
override fun ContentDrawScope.draw() {
|
||||
if (!isCacheValid) {
|
||||
observeReads { cacheDrawBlock() }
|
||||
isCacheValid = true
|
||||
}
|
||||
|
||||
drawContent()
|
||||
|
||||
val highlight = _highlight
|
||||
val graphicsLayer = graphicsLayer
|
||||
if (highlight != null && graphicsLayer != null) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val strokeWidth = ceil(highlight.width.toPx().fastCoerceAtMost(size.minDimension / 2f))
|
||||
graphicsLayer.renderEffect =
|
||||
highlight.style().createRenderEffect(size, strokeWidth)?.asComposeRenderEffect()
|
||||
}
|
||||
drawLayer(graphicsLayer)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onObservedReadsChanged() {
|
||||
invalidateDrawCache()
|
||||
}
|
||||
|
||||
fun invalidateDrawCache() {
|
||||
isCacheValid = false
|
||||
invalidateDraw()
|
||||
}
|
||||
|
||||
override fun onAttach() {
|
||||
val graphicsContext = requireGraphicsContext()
|
||||
graphicsLayer = graphicsContext.createGraphicsLayer()
|
||||
|
||||
@@ -6,11 +6,13 @@ import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffXfermode
|
||||
import android.graphics.RectF
|
||||
import android.os.Build
|
||||
import androidx.compose.ui.draw.CacheDrawModifierNode
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Outline
|
||||
import androidx.compose.ui.graphics.asAndroidPath
|
||||
import androidx.compose.ui.graphics.asComposePaint
|
||||
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
|
||||
import androidx.compose.ui.graphics.drawscope.DrawScope
|
||||
import androidx.compose.ui.graphics.drawscope.translate
|
||||
import androidx.compose.ui.graphics.isUnspecified
|
||||
import androidx.compose.ui.graphics.layer.CompositingStrategy
|
||||
@@ -18,8 +20,11 @@ import androidx.compose.ui.graphics.layer.GraphicsLayer
|
||||
import androidx.compose.ui.graphics.layer.drawLayer
|
||||
import androidx.compose.ui.graphics.nativeCanvas
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.node.DelegatingNode
|
||||
import androidx.compose.ui.node.DrawModifierNode
|
||||
import androidx.compose.ui.node.ModifierNodeElement
|
||||
import androidx.compose.ui.node.ObserverModifierNode
|
||||
import androidx.compose.ui.node.invalidateDraw
|
||||
import androidx.compose.ui.node.observeReads
|
||||
import androidx.compose.ui.node.requireGraphicsContext
|
||||
import androidx.compose.ui.platform.InspectorInfo
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
@@ -38,7 +43,7 @@ internal class ShadowElement(
|
||||
override fun update(node: ShadowNode) {
|
||||
node.shapeProvider = shapeProvider
|
||||
node.shadow = shadow
|
||||
node.drawNode.invalidateDrawCache()
|
||||
node.invalidateDrawCache()
|
||||
}
|
||||
|
||||
override fun InspectorInfo.inspectableProperties() {
|
||||
@@ -67,7 +72,7 @@ internal class ShadowElement(
|
||||
internal class ShadowNode(
|
||||
var shapeProvider: BackdropShapeProvider,
|
||||
var shadow: () -> Shadow?
|
||||
) : DelegatingNode() {
|
||||
) : DrawModifierNode, ObserverModifierNode, Modifier.Node() {
|
||||
|
||||
override val shouldAutoInvalidate: Boolean = false
|
||||
|
||||
@@ -82,13 +87,16 @@ internal class ShadowNode(
|
||||
}
|
||||
}
|
||||
|
||||
val drawNode = delegate(CacheDrawModifierNode {
|
||||
val shadow = shadow()
|
||||
private var _shadow: Shadow? = null
|
||||
private var isCacheValid = false
|
||||
private val cacheDrawBlock: DrawScope.() -> Unit = cacheDrawBlock@{
|
||||
val shadow = shadow().also { _shadow = it }
|
||||
val graphicsLayer = graphicsLayer
|
||||
if (shadow == null || graphicsLayer == null ||
|
||||
shadow.elevation.value <= 0f || shadow.color.isUnspecified
|
||||
) {
|
||||
return@CacheDrawModifierNode onDrawWithContent { drawContent() }
|
||||
_shadow = null
|
||||
return@cacheDrawBlock
|
||||
}
|
||||
|
||||
val size = size
|
||||
@@ -138,14 +146,34 @@ internal class ShadowNode(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onDrawWithContent {
|
||||
translate(-(elevation - offset.x), -(elevation - offset.y)) {
|
||||
override fun ContentDrawScope.draw() {
|
||||
if (!isCacheValid) {
|
||||
observeReads { cacheDrawBlock() }
|
||||
isCacheValid = true
|
||||
}
|
||||
|
||||
val shadow = _shadow
|
||||
val graphicsLayer = graphicsLayer
|
||||
if (shadow != null && graphicsLayer != null) {
|
||||
val elevation = shadow.elevation.toPx()
|
||||
translate(-(elevation - shadow.offset.x.toPx()), -(elevation - shadow.offset.y.toPx())) {
|
||||
drawLayer(graphicsLayer)
|
||||
}
|
||||
drawContent()
|
||||
}
|
||||
})
|
||||
|
||||
drawContent()
|
||||
}
|
||||
|
||||
override fun onObservedReadsChanged() {
|
||||
invalidateDrawCache()
|
||||
}
|
||||
|
||||
fun invalidateDrawCache() {
|
||||
isCacheValid = false
|
||||
invalidateDraw()
|
||||
}
|
||||
|
||||
override fun onAttach() {
|
||||
val graphicsContext = requireGraphicsContext()
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in new issue
Block a user