Özel boyacı

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

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

Painter, kesin olarak kendisine verilen sınırlar içinde kalan ve composable'ın ölçümü veya düzeni üzerinde etkisi olmayan DrawModifier öğesinden farklıdır.

Özel boyacı oluşturmak için Painter sınıfını genişletin ve özel grafikler çizmek için DrawScope öğesine erişim sağlayan onDraw yöntemini uygulayın. Ayrıca, içerdiği Composable'ı etkilemek için kullanılacak olan intrinsicSize öğesini 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
    }
}

Artık özel Painter öğemize sahip olduğumuza göre, herhangi bir resmi kaynak resmimizin üstüne aşağıdaki şekilde 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 boyacıyla birleştirmekten elde edilen sonuç aşağıda verilmiştir:

İki resmi üst üste yerleştiren özel boyacı
Şekil 1: İki resmi birbirinin üzerine kaplayan Özel Boyacı

Özel boya ustası, içeriği aşağıdaki gibi bir composable'a ç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 **/ }