Pittura personalizzata

In Compose, un oggetto Painter viene utilizzato per rappresentare qualcosa che può essere disegnato (un sostituto delle API Drawable definite in Android) e influenzare la misurazione e il layout del composable corrispondente che lo utilizza . Un BitmapPainter prende un ImageBitmap che può disegnare un Bitmap sullo schermo.

Per la maggior parte dei casi d'uso, l'utilizzo di painterResource() sopra restituisce il pittore corretto per la risorsa (ovvero BitmapPainter o VectorPainter). Per ulteriori informazioni sulle differenze tra i due, leggi la sezione ImageBitmap e ImageVector.

Un Painter è diverso da un DrawModifier, che viene disegnato rigorosamente all'interno dei limiti che gli vengono assegnati e non influisce sulla misurazione o sul layout del composable.

Per creare un pittore personalizzato, espandi la classe Painter e implementa il metodo onDraw, che consente di accedere a DrawScope per disegnare elementi grafici personalizzati. Puoi anche sostituire intrinsicSize, che verrà utilizzato per influenzare il Composable in cui è contenuto:

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

Ora che abbiamo il nostro Painter personalizzato, possiamo sovrapporre qualsiasi immagine all'immagine di origine come segue:

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

Di seguito è riportato l'output della combinazione delle due immagini con un pittore personalizzato:

Custom Painter che sovrappone due immagini una sull&#39;altra
Figura 1: Custom Painter che sovrappone due immagini una sopra l'altra

Un pittore personalizzato può essere utilizzato anche con Modifier.paint(customPainter) per disegnare i contenuti in un composable come segue:

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