Özel boyacı

Compose'da, çizilebilen bir öğeyi temsil etmek (Android'de tanımlanan Drawable API'lerinin yerine) ve bunu kullanan ilgili kompozisyonun ölçümünü ve düzenini etkilemek için bir Painter nesnesi kullanılır . BitmapPainter, ekranda Bitmap çizebilen bir ImageBitmap alır.

Çoğu kullanım alanında, yukarıdaki painterResource() kullanıldığında öğe için doğru boyayıcı (ör. BitmapPainter veya VectorPainter) döndürülür. İkisi arasındaki farklar hakkında daha fazla bilgi için ImageBitmap ve ImageVector karşılaştırması bölümünü okuyun.

Painter, kendisine verilen sınırlar içinde çizilen ve bileşenin ölçümü veya düzeni üzerinde hiçbir etkisi olmayan DrawModifier'ten farklıdır.

Özel bir boyayıcı oluşturmak için Painter sınıfını genişletin ve özel grafikler çizmek üzere DrawScope erişimine izin veren onDraw yöntemini uygulayın. Ayrıca, bulunduğu Composable'ı etkilemek için kullanılacak intrinsicSize değerini de geçersiz kılabilirsiniz:

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(
                this@onDraw.size.width.roundToInt(),
                this@onDraw.size.height.roundToInt()
            )
        )
        // draw the second image with an Overlay blend mode to blend the two together
        drawImage(
            imageOverlay,
            srcOffset,
            overlaySize,
            dstSize = IntSize(
                this@onDraw.size.width.roundToInt(),
                this@onDraw.size.height.roundToInt()
            ),
            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
    }
}

Özel Painter'imiz hazır olduğuna göre, herhangi bir resmi kaynak resmimizin üzerine aşağıdaki gibi yerleştirebiliriz:

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

İki resmi özel bir boya fırçasıyla birleştirmenin sonucunu aşağıda görebilirsiniz:

İki resmin birbirinin üzerine bindirildiği özel boyama aracı
Şekil 1: İki resmin üzerine bindiren özel boyama aracı

Özel bir boyacı, içeriği aşağıdaki gibi bir kompozisyona çizmek için Modifier.paint(customPainter) ile de kullanılabilir:

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