自定义画笔

在 Compose 中,一个 Painter 对象用于表示可以绘制的内容(Android 中定义的 Drawable API 的替代),并影响使用它的相应可组合项的测量和布局。一个 BitmapPainter 获取一个 ImageBitmap,该 ImageBitmap 可以在屏幕上绘制一个 Bitmap

对于大多数用例,使用上面的 painterResource() 会返回资产的正确绘制器(即 BitmapPainterVectorPainter)。有关两者之间差异的更多信息,请阅读 ImageBitmap 与 ImageVector 部分。

PainterDrawModifier 不同,后者严格地在给定的边界内绘制,并且对可组合项的测量或布局没有任何影响。

要创建自定义绘制器,请扩展 Painter 类并实现 onDraw 方法,该方法允许访问 DrawScope 以绘制自定义图形。您还可以覆盖 intrinsicSize,它将用于影响包含它的可组合项。

class OverlayImagePainter constructor(
    private val image: ImageBitmap,
    private val imageOverlay: ImageBitmap,
    private val srcOffset: IntOffset = IntOffset.Zero,
    private val srcSize: IntSize = IntSize(image.width, image.height),
    private val overlaySize: IntSize = IntSize(imageOverlay.width, imageOverlay.height)
) : Painter() {

    private val size: IntSize = validateSize(srcOffset, srcSize)
    override fun DrawScope.onDraw() {
        // draw the first image without any blend mode
        drawImage(
            image,
            srcOffset,
            srcSize,
            dstSize = IntSize(
                [email protected](),
                [email protected]()
            )
        )
        // draw the second image with an Overlay blend mode to blend the two together
        drawImage(
            imageOverlay,
            srcOffset,
            overlaySize,
            dstSize = IntSize(
                [email protected](),
                [email protected]()
            ),
            blendMode = BlendMode.Overlay
        )
    }

    /**
     * Return the dimension of the underlying [ImageBitmap] as it's intrinsic width and height
     */
    override val intrinsicSize: Size get() = size.toSize()

    private fun validateSize(srcOffset: IntOffset, srcSize: IntSize): IntSize {
        require(
            srcOffset.x >= 0 &&
                srcOffset.y >= 0 &&
                srcSize.width >= 0 &&
                srcSize.height >= 0 &&
                srcSize.width <= image.width &&
                srcSize.height <= image.height
        )
        return srcSize
    }
}

现在我们有了自定义的 Painter,我们可以按如下方式将任何图像叠加到我们的源图像上。

val rainbowImage = ImageBitmap.imageResource(id = R.drawable.rainbow)
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog)
val customPainter = remember {
    OverlayImagePainter(dogImage, rainbowImage)
}
Image(
    painter = customPainter,
    contentDescription = stringResource(id = R.string.dog_content_description),
    contentScale = ContentScale.Crop,
    modifier = Modifier.wrapContentSize()
)

使用自定义绘制器组合两个图像的输出如下所示。

Custom Painter that overlays two images on top of each other
图 1:将两个图像叠加在一起的自定义绘制器

自定义绘制器还可以与 Modifier.paint(customPainter) 一起使用,以将内容绘制到可组合项,如下所示。

val rainbowImage = ImageBitmap.imageResource(id = R.drawable.rainbow)
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog)
val customPainter = remember {
    OverlayImagePainter(dogImage, rainbowImage)
}
Box(
    modifier =
    Modifier.background(color = Color.Gray)
        .padding(30.dp)
        .background(color = Color.Yellow)
        .paint(customPainter)
) { /** intentionally empty **/ }