Android Compose:在图像上绘制透明圆

9
我有一张图片,想在它上面画一个带透明圆的黑色矩形,使结果类似于此图:https://www.google.com/url?sa=i&url=https%3A%2F%2Fstackoverflow.com%2Fquestions%2F36763696%2Fhow-to-create-a-transparent-circle-inside-rectangle-shape-in-xml-in-android&psig=AOvVaw18ZjvY-j8QyYzFw1xsmOdJ&ust=1630768957499000&source=images&cd=vfe&ved=0CAsQjRxqFwoTCPD1mveN4_ICFQAAAAAdAAAAABAE 我已经写好了以下代码:
Box(modifier = Modifier
        .clip(RectangleShape)
        .fillMaxSize()
        .background(Color.Black)
        .pointerInput(Unit) {
            detectTransformGestures { centroid, pan, zoom, rotation ->
                scale *= zoom
            }
        }) {
        Image(
            modifier = Modifier
                .align(Alignment.Center)
                .graphicsLayer(
                    scaleX = maxOf(.2f, minOf(5f, scale)),
                    scaleY = maxOf(.2f, minOf(5f, scale))
                ),
            bitmap = bitmap.asImageBitmap(),
            contentDescription = null
        )
        Canvas(modifier = Modifier.fillMaxSize(), onDraw = {
            drawRect(Color.Black.copy(alpha = 0.8f))
            drawCircle(
                Color.Transparent,
                style = Fill,
                blendMode = BlendMode.Clear
            )
        })
    }

但是似乎它只是在图像顶部绘制了一个黑色圆圈,而不是清除暗矩形...
如果您能根据此圆圈的坐标建议如何裁剪图像,那将非常方便。
2个回答

22

在这种情况下,您需要使用clipPath

Canvas(modifier = Modifier.fillMaxSize(), onDraw = {
    val circlePath = Path().apply {
        addOval(Rect(center, size.minDimension / 2))
    }
    clipPath(circlePath, clipOp = ClipOp.Difference) {
        drawRect(SolidColor(Color.Black.copy(alpha = 0.8f)))
    }
})


3

你不一定需要使用clipPath,你也可以使用Porterduff(BlendMode)模式,这实际上是首选方式,当你检查示例代码或问题以清除或删除一些像素或操作像素时。

只需要对你的代码进行小修改即可使其工作,你可以查看我的答案,了解如何应用Porterduff模式在这里

1- 添加具有透明度小于1f的图形层

.graphicsLayer {
    alpha = .99f
}

问题将被修复。

完整的实现

Box(
    modifier = Modifier
        .background(Color.Black)
        .fillMaxSize()
) {

    Image(
        modifier = Modifier.fillMaxSize(),
        painter = painterResource(id = R.drawable.landscape),
        contentScale = ContentScale.Crop,
        contentDescription = null
    )
    Canvas(
        modifier = Modifier
            .fillMaxSize()
            // ONLY ADD THIS
            .graphicsLayer {
                alpha = .99f
            }
    ) {

        // Destination
        drawRect(Color.Black.copy(alpha = 0.8f))

        // Source
        drawCircle(
            color = Color.Transparent,
            blendMode = BlendMode.Clear
        )

    }
}

2- 保存到图层

with(drawContext.canvas.nativeCanvas) {
    val checkPoint = saveLayer(null, null)

    // Destination
    drawRect(Color.Black.copy(alpha = 0.8f))

    // Source
    drawCircle(
        color = Color.Transparent,
        blendMode = BlendMode.Clear
    )
    restoreToCount(checkPoint)
}

完整实现

    Canvas(modifier = Modifier
        .fillMaxSize()
    ) {

        with(drawContext.canvas.nativeCanvas) {
            val checkPoint = saveLayer(null, null)

            // Destination
            drawRect(Color.Black.copy(alpha = 0.8f))

            // Source
            drawCircle(
                color = Color.Transparent,
                blendMode = BlendMode.Clear
            )
            restoreToCount(checkPoint)
        }
    }
}

结果

enter image description here

此外,您可以在这里查看混合模式、路径操作以及有关画布的更多信息。


谢谢,我想实际上使用这个透明圆来裁剪一张图片。 - Demigod

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接