Özel boyacı

Compose'da Painter nesnesi, çizilebilecek bir şeyi (Android'de tanımlanan Drawable API'lerinin yerine) temsil etmek ve onu kullanan karşılık gelen composable'ın ölçümünü ve düzenini etkilemek için kullanılır . BitmapPainter, ekranda Bitmap çizebilecek bir ImageBitmap alır.

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

Painter, kendisine verilen sınırların içinde sıkıca çizilen ve composable'ın ölçümü ya da düzeni üzerinde hiçbir etkisi olmayan bir DrawModifier'dan farklıdır.

Özel bir boyacı oluşturmak için Painter sınıfını genişletin ve özel grafikler çizmek için DrawScope erişimine izin veren onDraw yöntemini uygulayın. Ayrıca, yer aldığı Oluşturulabilir öğesini etkilemek için kullanılacak intrinsicSize öğesini 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
    }
}

Artık özel Painter öğemize sahip olduğumuza göre, aşağıdaki gibi herhangi bir resmi kaynak resmimizin üzerine 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ştirmenin sonucu aşağıda görülebilir:

İki resmi birbirinin üzerine yerleştiren Özel Boyacı
Şekil 1: İki resmi birbirinin üzerine yerleştiren Özel Boyacı

Özel bir boyacı, içeriği aşağıdaki şekilde 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 **/ }