Fix dispersion doesn't take effect in block modifier variant, extract common code
This commit is contained in:
1 parent
e9b69a6206
commit
11f1575e67
1 file changed
+153
-193
@@ -193,10 +193,162 @@ private class SimpleLiquidGlassNode(
|
|||||||
private var position: Offset by mutableStateOf(Offset.Zero)
|
private var position: Offset by mutableStateOf(Offset.Zero)
|
||||||
private var graphicsLayer: GraphicsLayer? = null
|
private var graphicsLayer: GraphicsLayer? = null
|
||||||
|
|
||||||
|
private val drawer = object : LiquidGlassDrawer() {
|
||||||
|
|
||||||
|
override val state: LiquidGlassProviderState get() = this@SimpleLiquidGlassNode.state
|
||||||
|
|
||||||
|
override val style: GlassStyle get() = this@SimpleLiquidGlassNode.style
|
||||||
|
|
||||||
|
override val transformBlock: (DrawTransform.() -> Unit)? get() = this@SimpleLiquidGlassNode.transformBlock
|
||||||
|
|
||||||
|
override val position: Offset get() = this@SimpleLiquidGlassNode.position
|
||||||
|
|
||||||
|
override val graphicsLayer: GraphicsLayer? get() = this@SimpleLiquidGlassNode.graphicsLayer
|
||||||
|
}
|
||||||
|
|
||||||
|
private val drawNode = delegate(drawer.drawNode)
|
||||||
|
|
||||||
|
override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
|
||||||
|
if (coordinates.isAttached) {
|
||||||
|
val providerPosition = state.position
|
||||||
|
position = coordinates.positionOnScreen() - providerPosition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAttach() {
|
||||||
|
val graphicsContext = requireGraphicsContext()
|
||||||
|
graphicsLayer =
|
||||||
|
graphicsContext.createGraphicsLayer().apply {
|
||||||
|
compositingStrategy = androidx.compose.ui.graphics.layer.CompositingStrategy.Offscreen
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDetach() {
|
||||||
|
val graphicsContext = requireGraphicsContext()
|
||||||
|
graphicsLayer?.let { layer ->
|
||||||
|
graphicsContext.releaseGraphicsLayer(layer)
|
||||||
|
graphicsLayer = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update(
|
||||||
|
state: LiquidGlassProviderState,
|
||||||
|
style: GlassStyle,
|
||||||
|
transformBlock: (DrawTransform.() -> Unit)?
|
||||||
|
) {
|
||||||
|
if (this.state != state ||
|
||||||
|
this.style != style ||
|
||||||
|
this.transformBlock != transformBlock
|
||||||
|
) {
|
||||||
|
this.state = state
|
||||||
|
this.style = style
|
||||||
|
this.transformBlock = transformBlock
|
||||||
|
drawNode.invalidateDrawCache()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||||
|
private class LiquidGlassNode(
|
||||||
|
var state: LiquidGlassProviderState,
|
||||||
|
var style: () -> GlassStyle,
|
||||||
|
var transformBlock: (DrawTransform.() -> Unit)?
|
||||||
|
) : GlobalPositionAwareModifierNode, ObserverModifierNode, DelegatingNode() {
|
||||||
|
|
||||||
|
override val shouldAutoInvalidate: Boolean = false
|
||||||
|
|
||||||
|
private var position: Offset by mutableStateOf(Offset.Zero)
|
||||||
|
private var graphicsLayer: GraphicsLayer? = null
|
||||||
|
|
||||||
|
private var currentStyle = style()
|
||||||
|
|
||||||
|
private val drawer = object : LiquidGlassDrawer() {
|
||||||
|
|
||||||
|
override val state: LiquidGlassProviderState get() = this@LiquidGlassNode.state
|
||||||
|
|
||||||
|
override val style: GlassStyle get() = currentStyle
|
||||||
|
|
||||||
|
override val transformBlock: (DrawTransform.() -> Unit)? get() = this@LiquidGlassNode.transformBlock
|
||||||
|
|
||||||
|
override val position: Offset get() = this@LiquidGlassNode.position
|
||||||
|
|
||||||
|
override val graphicsLayer: GraphicsLayer? get() = this@LiquidGlassNode.graphicsLayer
|
||||||
|
}
|
||||||
|
|
||||||
|
private val drawNode = delegate(drawer.drawNode)
|
||||||
|
|
||||||
|
override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
|
||||||
|
if (coordinates.isAttached) {
|
||||||
|
val providerPosition = state.position
|
||||||
|
position = coordinates.positionOnScreen() - providerPosition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onObservedReadsChanged() {
|
||||||
|
updateStyle()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAttach() {
|
||||||
|
val graphicsContext = requireGraphicsContext()
|
||||||
|
graphicsLayer =
|
||||||
|
graphicsContext.createGraphicsLayer().apply {
|
||||||
|
compositingStrategy = androidx.compose.ui.graphics.layer.CompositingStrategy.Offscreen
|
||||||
|
}
|
||||||
|
|
||||||
|
updateStyle()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDetach() {
|
||||||
|
val graphicsContext = requireGraphicsContext()
|
||||||
|
graphicsLayer?.let { layer ->
|
||||||
|
graphicsContext.releaseGraphicsLayer(layer)
|
||||||
|
graphicsLayer = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update(
|
||||||
|
state: LiquidGlassProviderState,
|
||||||
|
style: () -> GlassStyle,
|
||||||
|
transformBlock: (DrawTransform.() -> Unit)?
|
||||||
|
) {
|
||||||
|
if (this.state != state ||
|
||||||
|
this.style != style
|
||||||
|
) {
|
||||||
|
this.state = state
|
||||||
|
this.style = style
|
||||||
|
updateStyle()
|
||||||
|
}
|
||||||
|
if (this.transformBlock != transformBlock) {
|
||||||
|
this.transformBlock = transformBlock
|
||||||
|
drawNode.invalidateDrawCache()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateStyle() {
|
||||||
|
observeReads { currentStyle = style() }
|
||||||
|
drawNode.invalidateDrawCache()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||||
|
private abstract class LiquidGlassDrawer {
|
||||||
|
|
||||||
|
abstract val state: LiquidGlassProviderState
|
||||||
|
|
||||||
|
abstract val style: GlassStyle
|
||||||
|
|
||||||
|
abstract val transformBlock: (DrawTransform.() -> Unit)?
|
||||||
|
|
||||||
|
abstract val position: Offset
|
||||||
|
|
||||||
|
abstract val graphicsLayer: GraphicsLayer?
|
||||||
|
|
||||||
private val innerRefractionShader = RuntimeShader(GlassShaders.refractionShaderString)
|
private val innerRefractionShader = RuntimeShader(GlassShaders.refractionShaderString)
|
||||||
private var dispersionShader: RuntimeShader? = null
|
private var dispersionShader: RuntimeShader? = null
|
||||||
|
|
||||||
private val drawNode = delegate(CacheDrawModifierNode {
|
val drawNode = CacheDrawModifierNode {
|
||||||
|
val style = style
|
||||||
|
|
||||||
val colorFilter = style.material.colorFilter
|
val colorFilter = style.material.colorFilter
|
||||||
val colorFilterEffect =
|
val colorFilterEffect =
|
||||||
if (colorFilter != null) {
|
if (colorFilter != null) {
|
||||||
@@ -324,197 +476,5 @@ private class SimpleLiquidGlassNode(
|
|||||||
drawLayer(layer)
|
drawLayer(layer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
|
|
||||||
if (coordinates.isAttached) {
|
|
||||||
val providerPosition = state.position
|
|
||||||
position = coordinates.positionOnScreen() - providerPosition
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAttach() {
|
|
||||||
val graphicsContext = requireGraphicsContext()
|
|
||||||
graphicsLayer =
|
|
||||||
graphicsContext.createGraphicsLayer().apply {
|
|
||||||
compositingStrategy = androidx.compose.ui.graphics.layer.CompositingStrategy.Offscreen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDetach() {
|
|
||||||
val graphicsContext = requireGraphicsContext()
|
|
||||||
graphicsLayer?.let { layer ->
|
|
||||||
graphicsContext.releaseGraphicsLayer(layer)
|
|
||||||
graphicsLayer = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun update(
|
|
||||||
state: LiquidGlassProviderState,
|
|
||||||
style: GlassStyle,
|
|
||||||
transformBlock: (DrawTransform.() -> Unit)?
|
|
||||||
) {
|
|
||||||
if (this.state != state ||
|
|
||||||
this.style != style ||
|
|
||||||
this.transformBlock != transformBlock
|
|
||||||
) {
|
|
||||||
this.state = state
|
|
||||||
this.style = style
|
|
||||||
this.transformBlock = transformBlock
|
|
||||||
drawNode.invalidateDrawCache()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
|
||||||
private class LiquidGlassNode(
|
|
||||||
var state: LiquidGlassProviderState,
|
|
||||||
var style: () -> GlassStyle,
|
|
||||||
var transformBlock: (DrawTransform.() -> Unit)?
|
|
||||||
) : GlobalPositionAwareModifierNode, ObserverModifierNode, DelegatingNode() {
|
|
||||||
|
|
||||||
override val shouldAutoInvalidate: Boolean = false
|
|
||||||
|
|
||||||
private var position: Offset by mutableStateOf(Offset.Zero)
|
|
||||||
private var graphicsLayer: GraphicsLayer? = null
|
|
||||||
|
|
||||||
private var currentStyle = style()
|
|
||||||
|
|
||||||
private val innerRefractionShader = RuntimeShader(GlassShaders.refractionShaderString)
|
|
||||||
|
|
||||||
private val drawNode = delegate(CacheDrawModifierNode {
|
|
||||||
val style = currentStyle
|
|
||||||
|
|
||||||
val colorFilter = style.material.colorFilter
|
|
||||||
val colorFilterEffect =
|
|
||||||
if (colorFilter != null) {
|
|
||||||
RenderEffect.createColorFilterEffect(colorFilter.asAndroidColorFilter())
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
val blurRadiusPx = style.material.blurRadius.toPx()
|
|
||||||
val blurRenderEffect =
|
|
||||||
if (blurRadiusPx > 0f) {
|
|
||||||
if (colorFilterEffect != null) {
|
|
||||||
RenderEffect.createBlurEffect(
|
|
||||||
blurRadiusPx,
|
|
||||||
blurRadiusPx,
|
|
||||||
colorFilterEffect,
|
|
||||||
Shader.TileMode.CLAMP
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
RenderEffect.createBlurEffect(
|
|
||||||
blurRadiusPx,
|
|
||||||
blurRadiusPx,
|
|
||||||
Shader.TileMode.CLAMP
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
colorFilterEffect
|
|
||||||
}
|
|
||||||
|
|
||||||
val cornerRadiusPx = style.shape.topStart.toPx(size, this)
|
|
||||||
|
|
||||||
val innerRefractionHeight = style.innerRefraction.height.toPx(size, this)
|
|
||||||
val innerRefractionAmount = style.innerRefraction.amount.toPx(size, this)
|
|
||||||
val depthEffect = style.innerRefraction.depthEffect
|
|
||||||
val innerRefractionRenderEffect =
|
|
||||||
RenderEffect.createRuntimeShaderEffect(
|
|
||||||
innerRefractionShader.apply {
|
|
||||||
setFloatUniform("size", size.width, size.height)
|
|
||||||
setFloatUniform("cornerRadius", cornerRadiusPx)
|
|
||||||
|
|
||||||
setFloatUniform("refractionHeight", innerRefractionHeight)
|
|
||||||
setFloatUniform("refractionAmount", innerRefractionAmount)
|
|
||||||
setFloatUniform("depthEffect", depthEffect)
|
|
||||||
},
|
|
||||||
"image"
|
|
||||||
)
|
|
||||||
|
|
||||||
val renderEffect =
|
|
||||||
if (blurRenderEffect != null) {
|
|
||||||
RenderEffect.createChainEffect(
|
|
||||||
innerRefractionRenderEffect,
|
|
||||||
blurRenderEffect
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
innerRefractionRenderEffect
|
|
||||||
}.asComposeRenderEffect()
|
|
||||||
|
|
||||||
graphicsLayer?.renderEffect = renderEffect
|
|
||||||
graphicsLayer?.record {
|
|
||||||
val transformBlock = transformBlock
|
|
||||||
val position = position
|
|
||||||
if (transformBlock != null) {
|
|
||||||
withTransform(transformBlock) {
|
|
||||||
translate(-position.x, -position.y) {
|
|
||||||
drawLayer(state.graphicsLayer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
translate(-position.x, -position.y) {
|
|
||||||
drawLayer(state.graphicsLayer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onDrawBehind {
|
|
||||||
graphicsLayer?.let { layer ->
|
|
||||||
drawLayer(layer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
override fun onGloballyPositioned(coordinates: LayoutCoordinates) {
|
|
||||||
if (coordinates.isAttached) {
|
|
||||||
val providerPosition = state.position
|
|
||||||
position = coordinates.positionOnScreen() - providerPosition
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onObservedReadsChanged() {
|
|
||||||
updateStyle()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAttach() {
|
|
||||||
val graphicsContext = requireGraphicsContext()
|
|
||||||
graphicsLayer =
|
|
||||||
graphicsContext.createGraphicsLayer().apply {
|
|
||||||
compositingStrategy = androidx.compose.ui.graphics.layer.CompositingStrategy.Offscreen
|
|
||||||
}
|
|
||||||
|
|
||||||
updateStyle()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDetach() {
|
|
||||||
val graphicsContext = requireGraphicsContext()
|
|
||||||
graphicsLayer?.let { layer ->
|
|
||||||
graphicsContext.releaseGraphicsLayer(layer)
|
|
||||||
graphicsLayer = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun update(
|
|
||||||
state: LiquidGlassProviderState,
|
|
||||||
style: () -> GlassStyle,
|
|
||||||
transformBlock: (DrawTransform.() -> Unit)?
|
|
||||||
) {
|
|
||||||
if (this.state != state ||
|
|
||||||
this.style != style
|
|
||||||
) {
|
|
||||||
this.state = state
|
|
||||||
this.style = style
|
|
||||||
updateStyle()
|
|
||||||
}
|
|
||||||
if (this.transformBlock != transformBlock) {
|
|
||||||
this.transformBlock = transformBlock
|
|
||||||
drawNode.invalidateDrawCache()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateStyle() {
|
|
||||||
observeReads { currentStyle = style() }
|
|
||||||
drawNode.invalidateDrawCache()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user