Merge Modifier.contentBackdrop into Modifier.drawBackdrop
This commit is contained in:
1 parent
f23b9e5408
commit
00e9479e32
3 files changed
+91
-308
No files matched your search
@@ -1,264 +0,0 @@
|
||||
package com.kyant.backdrop
|
||||
|
||||
import android.os.Build
|
||||
import androidx.compose.ui.Modifier
|
||||
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.drawscope.withTransform
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
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.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
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import com.kyant.backdrop.highlight.Highlight
|
||||
import com.kyant.backdrop.highlight.HighlightElement
|
||||
import com.kyant.backdrop.shadow.Shadow
|
||||
import com.kyant.backdrop.shadow.ShadowElement
|
||||
|
||||
fun Modifier.contentBackdrop(
|
||||
shape: () -> Shape,
|
||||
highlight: (() -> Highlight?)? = DefaultHighlight,
|
||||
shadow: (() -> Shadow?)? = DefaultShadow,
|
||||
layer: (GraphicsLayerScope.() -> Unit)? = null,
|
||||
drawContent: Boolean = false,
|
||||
onDrawBehind: (DrawScope.() -> Unit)? = null,
|
||||
onDrawSurface: (DrawScope.() -> Unit)? = null,
|
||||
effects: BackdropEffectScope.() -> Unit
|
||||
): Modifier {
|
||||
val shapeProvider = ShapeProvider(shape)
|
||||
return this
|
||||
.then(
|
||||
if (layer != null) {
|
||||
Modifier.graphicsLayer(layer)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
)
|
||||
.then(
|
||||
if (shadow != null) {
|
||||
ShadowElement(
|
||||
shapeProvider = shapeProvider,
|
||||
shadow = shadow
|
||||
)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
)
|
||||
.then(
|
||||
if (highlight != null) {
|
||||
HighlightElement(
|
||||
shapeProvider = shapeProvider,
|
||||
highlight = highlight
|
||||
)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
)
|
||||
.then(
|
||||
ContentBackdropElement(
|
||||
shapeProvider = shapeProvider,
|
||||
layer = layer,
|
||||
drawContent = drawContent,
|
||||
onDrawBehind = onDrawBehind,
|
||||
onDrawSurface = onDrawSurface,
|
||||
effects = effects
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private class ContentBackdropElement(
|
||||
val shapeProvider: ShapeProvider,
|
||||
val layer: (GraphicsLayerScope.() -> Unit)?,
|
||||
val drawContent: Boolean,
|
||||
val onDrawBehind: (DrawScope.() -> Unit)?,
|
||||
val onDrawSurface: (DrawScope.() -> Unit)?,
|
||||
val effects: BackdropEffectScope.() -> Unit
|
||||
) : ModifierNodeElement<ContentBackdropNode>() {
|
||||
|
||||
override fun create(): ContentBackdropNode {
|
||||
return ContentBackdropNode(
|
||||
shapeProvider = shapeProvider,
|
||||
layer = layer,
|
||||
drawContent = drawContent,
|
||||
onDrawBehind = onDrawBehind,
|
||||
onDrawSurface = onDrawSurface,
|
||||
effects = effects
|
||||
)
|
||||
}
|
||||
|
||||
override fun update(node: ContentBackdropNode) {
|
||||
node.shapeProvider = shapeProvider
|
||||
node.layer = layer
|
||||
node.drawContent = drawContent
|
||||
node.onDrawBehind = onDrawBehind
|
||||
node.onDrawSurface = onDrawSurface
|
||||
node.effects = effects
|
||||
node.invalidateDrawCache()
|
||||
}
|
||||
|
||||
override fun InspectorInfo.inspectableProperties() {
|
||||
name = "contentBackdrop"
|
||||
properties["shapeProvider"] = shapeProvider
|
||||
properties["layer"] = layer
|
||||
properties["drawContent"] = drawContent
|
||||
properties["onDrawBehind"] = onDrawBehind
|
||||
properties["onDrawSurface"] = onDrawSurface
|
||||
properties["effects"] = effects
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other !is ContentBackdropElement) return false
|
||||
|
||||
if (shapeProvider != other.shapeProvider) return false
|
||||
if (layer != other.layer) return false
|
||||
if (drawContent != other.drawContent) return false
|
||||
if (onDrawBehind != other.onDrawBehind) return false
|
||||
if (onDrawSurface != other.onDrawSurface) return false
|
||||
if (effects != other.effects) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = shapeProvider.hashCode()
|
||||
result = 31 * result + (layer?.hashCode() ?: 0)
|
||||
result = 31 * result + drawContent.hashCode()
|
||||
result = 31 * result + (onDrawBehind?.hashCode() ?: 0)
|
||||
result = 31 * result + (onDrawSurface?.hashCode() ?: 0)
|
||||
result = 31 * result + effects.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
private class ContentBackdropNode(
|
||||
var shapeProvider: ShapeProvider,
|
||||
var layer: (GraphicsLayerScope.() -> Unit)?,
|
||||
var drawContent: Boolean,
|
||||
var onDrawBehind: (DrawScope.() -> Unit)?,
|
||||
var onDrawSurface: (DrawScope.() -> Unit)?,
|
||||
var effects: BackdropEffectScope.() -> Unit
|
||||
) : LayoutModifierNode, DrawModifierNode, ObserverModifierNode, Modifier.Node() {
|
||||
|
||||
override val shouldAutoInvalidate: Boolean = false
|
||||
|
||||
private var graphicsLayer: GraphicsLayer? = null
|
||||
|
||||
private val effectScope =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
object : BackdropEffectScopeImpl() {
|
||||
|
||||
override val shape: Shape get() = shapeProvider.innerShape
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
private val layerBlock: GraphicsLayerScope.() -> Unit = {
|
||||
clip = true
|
||||
shape = shapeProvider.shape
|
||||
compositingStrategy = androidx.compose.ui.graphics.CompositingStrategy.Offscreen
|
||||
}
|
||||
|
||||
private var inverseLayerScope: InverseLayerScope? = null
|
||||
|
||||
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() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
if (effectScope != null && effectScope.update(this)) {
|
||||
updateEffects()
|
||||
}
|
||||
}
|
||||
|
||||
onDrawBehind?.invoke(this)
|
||||
|
||||
val layer = graphicsLayer
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && layer != null) {
|
||||
layer.record { this@draw.drawContent() }
|
||||
|
||||
val layerBlock = this@ContentBackdropNode.layer
|
||||
if (layerBlock != null) {
|
||||
withTransform({
|
||||
val inverseLayerScope =
|
||||
inverseLayerScope?.apply { reset() }
|
||||
?: InverseLayerScope().also { inverseLayerScope = it }
|
||||
with(inverseLayerScope) { inverseTransform(this@draw, layerBlock) }
|
||||
}) {
|
||||
drawLayer(layer)
|
||||
}
|
||||
} else {
|
||||
drawLayer(layer)
|
||||
}
|
||||
|
||||
if (drawContent) {
|
||||
drawContent()
|
||||
}
|
||||
} else {
|
||||
drawContent()
|
||||
}
|
||||
|
||||
onDrawSurface?.invoke(this)
|
||||
}
|
||||
|
||||
override fun onObservedReadsChanged() {
|
||||
invalidateDrawCache()
|
||||
}
|
||||
|
||||
fun invalidateDrawCache() {
|
||||
observeEffects()
|
||||
invalidateDraw()
|
||||
}
|
||||
|
||||
private fun observeEffects() {
|
||||
if (effectScope != null) {
|
||||
observeReads { updateEffects() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateEffects() {
|
||||
if (effectScope != null) {
|
||||
effectScope.renderEffect = null
|
||||
effects(effectScope)
|
||||
graphicsLayer?.renderEffect = effectScope.renderEffect?.asComposeRenderEffect()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttach() {
|
||||
val graphicsContext = requireGraphicsContext()
|
||||
graphicsLayer = graphicsContext.createGraphicsLayer()
|
||||
observeEffects()
|
||||
}
|
||||
|
||||
override fun onDetach() {
|
||||
val graphicsContext = requireGraphicsContext()
|
||||
graphicsLayer?.let { layer ->
|
||||
graphicsContext.releaseGraphicsLayer(layer)
|
||||
graphicsLayer = null
|
||||
}
|
||||
inverseLayerScope = null
|
||||
effectScope?.reset()
|
||||
}
|
||||
}
|
||||
@@ -25,21 +25,21 @@ 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.requireDensity
|
||||
import androidx.compose.ui.node.requireGraphicsContext
|
||||
import androidx.compose.ui.platform.InspectorInfo
|
||||
import androidx.compose.ui.unit.Constraints
|
||||
import androidx.compose.ui.unit.Density
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.toIntSize
|
||||
import com.kyant.backdrop.backdrops.LayerBackdrop
|
||||
import com.kyant.backdrop.highlight.Highlight
|
||||
import com.kyant.backdrop.highlight.HighlightElement
|
||||
import com.kyant.backdrop.shadow.Shadow
|
||||
import com.kyant.backdrop.shadow.ShadowElement
|
||||
|
||||
internal val DefaultHighlight = { Highlight.Default }
|
||||
internal val DefaultShadow = { Shadow.Default }
|
||||
private val DefaultHighlight = { Highlight.Default }
|
||||
private val DefaultShadow = { Shadow.Default }
|
||||
private val DefaultOnDrawBackdrop: DrawScope.(DrawScope.() -> Unit) -> Unit = { it() }
|
||||
private val DefaultOnDrawContent: ContentDrawScope.() -> Unit = { drawContent() }
|
||||
|
||||
fun Modifier.drawBackdrop(
|
||||
backdrop: Backdrop,
|
||||
@@ -51,8 +51,11 @@ fun Modifier.drawBackdrop(
|
||||
onDrawBehind: (DrawScope.() -> Unit)? = null,
|
||||
onDrawBackdrop: DrawScope.(drawBackdrop: DrawScope.() -> Unit) -> Unit = DefaultOnDrawBackdrop,
|
||||
onDrawSurface: (DrawScope.() -> Unit)? = null,
|
||||
onDrawContent: ContentDrawScope.() -> Unit = DefaultOnDrawContent,
|
||||
onDrawFront: (DrawScope.() -> Unit)? = null,
|
||||
effects: BackdropEffectScope.() -> Unit
|
||||
drawContent: Boolean = true,
|
||||
contentEffects: (BackdropEffectScope.() -> Unit)? = null,
|
||||
effects: (BackdropEffectScope.() -> Unit)? = null
|
||||
): Modifier {
|
||||
val shapeProvider = ShapeProvider(shape)
|
||||
return this
|
||||
@@ -92,7 +95,10 @@ fun Modifier.drawBackdrop(
|
||||
onDrawBehind = onDrawBehind,
|
||||
onDrawBackdrop = onDrawBackdrop,
|
||||
onDrawSurface = onDrawSurface,
|
||||
onDrawContent = onDrawContent,
|
||||
onDrawFront = onDrawFront,
|
||||
drawContent = drawContent,
|
||||
contentEffects = contentEffects,
|
||||
effects = effects
|
||||
)
|
||||
)
|
||||
@@ -106,8 +112,11 @@ private class DrawBackdropElement(
|
||||
val onDrawBehind: (DrawScope.() -> Unit)?,
|
||||
val onDrawBackdrop: DrawScope.(drawBackdrop: DrawScope.() -> Unit) -> Unit,
|
||||
val onDrawSurface: (DrawScope.() -> Unit)?,
|
||||
val onDrawContent: ContentDrawScope.() -> Unit,
|
||||
val onDrawFront: (DrawScope.() -> Unit)?,
|
||||
val effects: BackdropEffectScope.() -> Unit
|
||||
val drawContent: Boolean,
|
||||
val contentEffects: (BackdropEffectScope.() -> Unit)?,
|
||||
val effects: (BackdropEffectScope.() -> Unit)?
|
||||
) : ModifierNodeElement<DrawBackdropNode>() {
|
||||
|
||||
override fun create(): DrawBackdropNode {
|
||||
@@ -119,7 +128,10 @@ private class DrawBackdropElement(
|
||||
onDrawBehind = onDrawBehind,
|
||||
onDrawBackdrop = onDrawBackdrop,
|
||||
onDrawSurface = onDrawSurface,
|
||||
onDrawContent = onDrawContent,
|
||||
onDrawFront = onDrawFront,
|
||||
drawContent = drawContent,
|
||||
contentEffects = contentEffects,
|
||||
effects = effects
|
||||
)
|
||||
}
|
||||
@@ -132,7 +144,10 @@ private class DrawBackdropElement(
|
||||
node.onDrawBehind = onDrawBehind
|
||||
node.onDrawBackdrop = onDrawBackdrop
|
||||
node.onDrawSurface = onDrawSurface
|
||||
node.onDrawContent = onDrawContent
|
||||
node.onDrawFront = onDrawFront
|
||||
node.drawContent = drawContent
|
||||
node.contentEffects = contentEffects
|
||||
node.effects = effects
|
||||
node.invalidateDrawCache()
|
||||
}
|
||||
@@ -146,7 +161,10 @@ private class DrawBackdropElement(
|
||||
properties["onDrawBehind"] = onDrawBehind
|
||||
properties["onDrawBackdrop"] = onDrawBackdrop
|
||||
properties["onDrawSurface"] = onDrawSurface
|
||||
properties["onDrawContent"] = onDrawContent
|
||||
properties["onDrawFront"] = onDrawFront
|
||||
properties["drawContent"] = drawContent
|
||||
properties["contentEffects"] = contentEffects
|
||||
properties["effects"] = effects
|
||||
}
|
||||
|
||||
@@ -161,7 +179,10 @@ private class DrawBackdropElement(
|
||||
if (onDrawBehind != other.onDrawBehind) return false
|
||||
if (onDrawBackdrop != other.onDrawBackdrop) return false
|
||||
if (onDrawSurface != other.onDrawSurface) return false
|
||||
if (onDrawContent != other.onDrawContent) return false
|
||||
if (onDrawFront != other.onDrawFront) return false
|
||||
if (drawContent != other.drawContent) return false
|
||||
if (contentEffects != other.contentEffects) return false
|
||||
if (effects != other.effects) return false
|
||||
|
||||
return true
|
||||
@@ -175,7 +196,10 @@ private class DrawBackdropElement(
|
||||
result = 31 * result + (onDrawBehind?.hashCode() ?: 0)
|
||||
result = 31 * result + onDrawBackdrop.hashCode()
|
||||
result = 31 * result + (onDrawSurface?.hashCode() ?: 0)
|
||||
result = 31 * result + onDrawContent.hashCode()
|
||||
result = 31 * result + (onDrawFront?.hashCode() ?: 0)
|
||||
result = 31 * result + drawContent.hashCode()
|
||||
result = 31 * result + (contentEffects?.hashCode() ?: 0)
|
||||
result = 31 * result + effects.hashCode()
|
||||
return result
|
||||
}
|
||||
@@ -189,19 +213,24 @@ private class DrawBackdropNode(
|
||||
var onDrawBehind: (DrawScope.() -> Unit)?,
|
||||
var onDrawBackdrop: DrawScope.(drawBackdrop: DrawScope.() -> Unit) -> Unit,
|
||||
var onDrawSurface: (DrawScope.() -> Unit)?,
|
||||
var onDrawContent: ContentDrawScope.() -> Unit,
|
||||
var onDrawFront: (DrawScope.() -> Unit)?,
|
||||
var effects: BackdropEffectScope.() -> Unit
|
||||
var drawContent: Boolean,
|
||||
var contentEffects: (BackdropEffectScope.() -> Unit)?,
|
||||
var effects: (BackdropEffectScope.() -> Unit)?
|
||||
) : LayoutModifierNode, DrawModifierNode, GlobalPositionAwareModifierNode, ObserverModifierNode, Modifier.Node() {
|
||||
|
||||
override val shouldAutoInvalidate: Boolean = false
|
||||
|
||||
private var graphicsLayer: GraphicsLayer? = null
|
||||
private var contentGraphicsLayer: GraphicsLayer? = null
|
||||
|
||||
private var layoutCoordinates: LayoutCoordinates? by mutableStateOf(null, neverEqualPolicy())
|
||||
private val recordBlock: (DrawScope.() -> Unit) = {
|
||||
onDrawBackdrop {
|
||||
with(backdrop) {
|
||||
drawBackdrop(
|
||||
density = mutableDensity,
|
||||
density = requireDensity(),
|
||||
coordinates = layoutCoordinates,
|
||||
layerBlock = layer
|
||||
)
|
||||
@@ -225,13 +254,6 @@ private class DrawBackdropNode(
|
||||
compositingStrategy = androidx.compose.ui.graphics.CompositingStrategy.Offscreen
|
||||
}
|
||||
|
||||
private val mutableDensity = object : Density {
|
||||
|
||||
override var density: Float = 1f
|
||||
|
||||
override var fontScale: Float = 1f
|
||||
}
|
||||
|
||||
override fun MeasureScope.measure(
|
||||
measurable: Measurable,
|
||||
constraints: Constraints
|
||||
@@ -253,14 +275,7 @@ private class DrawBackdropNode(
|
||||
|
||||
val layer = graphicsLayer
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && layer != null) {
|
||||
mutableDensity.density = density
|
||||
mutableDensity.fontScale = fontScale
|
||||
layer.record(
|
||||
density = mutableDensity,
|
||||
layoutDirection = layoutDirection,
|
||||
size = size.toIntSize(),
|
||||
block = recordBlock
|
||||
)
|
||||
layer.record(block = recordBlock)
|
||||
drawLayer(layer)
|
||||
} else {
|
||||
recordBlock()
|
||||
@@ -268,15 +283,20 @@ private class DrawBackdropNode(
|
||||
|
||||
onDrawSurface?.invoke(this)
|
||||
|
||||
drawContent()
|
||||
val contentLayer = contentGraphicsLayer
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && contentLayer != null) {
|
||||
contentLayer.record { this@draw.onDrawContent() }
|
||||
|
||||
drawLayer(contentLayer)
|
||||
}
|
||||
|
||||
if (drawContent) {
|
||||
onDrawContent()
|
||||
}
|
||||
|
||||
onDrawFront?.invoke(this)
|
||||
|
||||
exportedBackdrop?.graphicsLayer?.record(
|
||||
density = mutableDensity,
|
||||
layoutDirection = layoutDirection,
|
||||
size = size.toIntSize()
|
||||
) {
|
||||
exportedBackdrop?.graphicsLayer?.record {
|
||||
onDrawBehind?.invoke(this)
|
||||
|
||||
val layer = graphicsLayer
|
||||
@@ -322,15 +342,44 @@ private class DrawBackdropNode(
|
||||
|
||||
private fun updateEffects() {
|
||||
if (effectScope != null) {
|
||||
effectScope.renderEffect = null
|
||||
effects(effectScope)
|
||||
graphicsLayer?.renderEffect = effectScope.renderEffect?.asComposeRenderEffect()
|
||||
val graphicsContext = requireGraphicsContext()
|
||||
|
||||
val backdropEffects = effects
|
||||
if (backdropEffects != null) {
|
||||
if (graphicsLayer == null) {
|
||||
graphicsLayer = graphicsContext.createGraphicsLayer()
|
||||
}
|
||||
|
||||
effectScope.renderEffect = null
|
||||
backdropEffects(effectScope)
|
||||
graphicsLayer?.renderEffect = effectScope.renderEffect?.asComposeRenderEffect()
|
||||
} else {
|
||||
graphicsLayer?.let { layer ->
|
||||
graphicsContext.releaseGraphicsLayer(layer)
|
||||
graphicsLayer = null
|
||||
}
|
||||
}
|
||||
|
||||
val contentEffects = contentEffects
|
||||
if (contentEffects != null) {
|
||||
if (contentGraphicsLayer == null) {
|
||||
val graphicsContext = requireGraphicsContext()
|
||||
contentGraphicsLayer = graphicsContext.createGraphicsLayer()
|
||||
}
|
||||
|
||||
effectScope.renderEffect = null
|
||||
contentEffects(effectScope)
|
||||
contentGraphicsLayer?.renderEffect = effectScope.renderEffect?.asComposeRenderEffect()
|
||||
} else {
|
||||
contentGraphicsLayer?.let { layer ->
|
||||
graphicsContext.releaseGraphicsLayer(layer)
|
||||
contentGraphicsLayer = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttach() {
|
||||
val graphicsContext = requireGraphicsContext()
|
||||
graphicsLayer = graphicsContext.createGraphicsLayer()
|
||||
observeEffects()
|
||||
}
|
||||
|
||||
@@ -340,6 +389,10 @@ private class DrawBackdropNode(
|
||||
graphicsContext.releaseGraphicsLayer(layer)
|
||||
graphicsLayer = null
|
||||
}
|
||||
contentGraphicsLayer?.let { layer ->
|
||||
graphicsContext.releaseGraphicsLayer(layer)
|
||||
contentGraphicsLayer = null
|
||||
}
|
||||
layoutCoordinates = null
|
||||
effectScope?.reset()
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user