I'm creating a custom component in Jetpack Compose that needs to be drawn beyond the component's bounds, Which might use transparent color in BlendMode. I'm using CompositingStrategy for handling this but facing some issues.
Below is the example recreation of the issue.
@Composable
@Preview(widthDp = 600, heightDp = 600)
private fun Preview() {
Column(
Modifier.fillMaxSize().background(Color.Blue),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Canvas(
modifier = Modifier.size(250.dp).graphicsLayer(
compositingStrategy = CompositingStrategy.Offscreen,
// compositingStrategy = CompositingStrategy.ModulateAlpha
).border(1.dp, color = Color.Black)
) {
drawCircle(
Color.Red,
(size.minDimension/2f)*1.5f
)
drawCircle(
Color.Transparent,
(size.minDimension/2f)*1f,
blendMode = BlendMode.Src
)
}
}
}
On using
CompositingStrategy.Offscreen
: Handles alpha correctly but clips the drawing to the component's size.
On using
CompositingStrategy.ModulateAlpha
: Solves the clipping issue, but transparent colors Inner Circle are not working.
So is there any way of achieving both of these at the same time?
Below is the Result i am expecting, where the inner circle is transparent, So the blue background is visible:
compositingStrategy = CompositingStrategy.Offscreen
clips content in Composable and Modifiers after it.
By default even if you can draw anything to any Composable even if their size is zero.
To apply Porter-Duff or blend modes correctly you can create a layer with
private fun DrawScope.drawWithLayer(block: DrawScope.() -> Unit) {
with(drawContext.canvas.nativeCanvas) {
val checkPoint = saveLayer(null, null)
block()
restoreToCount(checkPoint)
}
}
And draw inside it with
@Composable
@Preview(widthDp = 600, heightDp = 600)
private fun Preview() {
Column(
Modifier.fillMaxSize().background(Color.Blue),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Canvas(
modifier = Modifier.size(250.dp)
.border(1.dp, color = Color.Black)
) {
drawWithLayer {
drawCircle(
Color.Red,
(size.minDimension/2f)*1.5f
)
drawCircle(
Color.Transparent,
(size.minDimension/2f)*1f,
blendMode = BlendMode.Src
)
}
}
}
}