我正在尝试将混合模式应用于 Jetpack compose 画布中的两个形状。基于这个博客,我大致知道预期的输出应该是什么样子,尽管我没有得到类似的结果。
例如,使用以下简单的 Box + Canvas,具有两种形状,使用混合模式
SrcIn
Box(
contentAlignment = Alignment.Center,
modifier = Modifier.size(290.dp)
) {
val sizeInPx = with(LocalDensity.current) { 150.dp.toPx() }
Canvas(
modifier = Modifier.fillMaxSize()
) {
drawCircle(
color = Color.Red,
radius = sizeInPx,
)
drawRect(
color = Color.Blue,
size = Size(sizeInPx, sizeInPx),
blendMode = BlendMode.SrcIn
)
}
}
我期望有一个红色圆圈,以及一个剪裁成红色圆圈形状的蓝色正方形。然而输出的 UI 就像
我做错了什么?
将 alpha 更改为小于 1f 会创建一个图层作为缓冲区,这就是它起作用的原因。如果您不想更改 alpha,实现此目的的其他方法是直接使用图层。你可以在这里看到我的回答
Canvas(modifier = canvasModifier) {
val canvasWidth = size.width.roundToInt()
val canvasHeight = size.height.roundToInt()
with(drawContext.canvas.nativeCanvas) {
val checkPoint = saveLayer(null, null)
drawCircle(
color = Color.Red,
radius = sizeInPx,
)
drawRect(
color = Color.Blue,
size = Size(sizeInPx, sizeInPx),
blendMode = BlendMode.SrcIn
)
restoreToCount(checkPoint)
}
}
在 Painter 代码中,Android 团队将其用作
private fun configureAlpha(alpha: Float) {
if (this.alpha != alpha) {
val consumed = applyAlpha(alpha)
if (!consumed) {
if (alpha == DefaultAlpha) {
// Only update the paint parameter if we had it allocated before
layerPaint?.alpha = alpha
useLayer = false
} else {
obtainPaint().alpha = alpha
useLayer = true
}
}
this.alpha = alpha
}
}
并检查Alpha以应用图层
fun DrawScope.draw(
size: Size,
alpha: Float = DefaultAlpha,
colorFilter: ColorFilter? = null
) {
configureAlpha(alpha)
configureColorFilter(colorFilter)
configureLayoutDirection(layoutDirection)
// b/156512437 to expose saveLayer on DrawScope
inset(
left = 0.0f,
top = 0.0f,
right = this.size.width - size.width,
bottom = this.size.height - size.height
) {
if (alpha > 0.0f && size.width > 0 && size.height > 0) {
if (useLayer) {
val layerRect = Rect(Offset.Zero, Size(size.width, size.height))
// TODO (b/154550724) njawad replace with RenderNode/Layer API usage
drawIntoCanvas { canvas ->
canvas.withSaveLayer(layerRect, obtainPaint()) {
onDraw()
}
}
} else {
onDraw()
}
}
}
}
}
在所有其他绘制命令之前调用
drawRect(Color.White, blendMode = BlendMode.Clear)
使其在我这边工作。
看来,预先使用混合模式会创建底层,让其他混合模式完全得到尊重。