简体   繁体   中英

Jetpack compose Canvas blendmode not working as expected

I'm attempting to apply blend mode to two shapes within Jetpack compose's canvas. Based on this blog I know roughly what the expected output should look like though I am not getting similar results.

For example, with the following simple Box + Canvas with two shapes, with the blend mode 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
                    )

            }
}

I would expect a red circle, and a blue square clipped to the shape of the red circle. Yet the output UI is as if no blend mode has been added at all

What am I doing wrong?

Changing alpha less then 1f creates a layer as buffer that's why it works. Other way of achieving this is to use layer directly if you don't want to change alpha. You can see my answere about it here

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)
    }
}

In painter code Android team uses it as

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
    }
}

And check alpha to apply layer

  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()
                }
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM