En Compose, se usa un objeto Painter para representar algo que se puede
dibujar (un reemplazo de las APIs de Drawable definidas en Android). Este objeto también influye en la
medición y el diseño del elemento correspondiente componible que lo usa. Un
BitmapPainter toma una ImageBitmap que puede dibujar un Bitmap en la pantalla.
En la mayoría de los casos de uso, el uso de la función painterResource() muestra el pintor correcto
para el recurso (como BitmapPainter o VectorPainter). Para obtener más
información sobre las diferencias entre los dos, lee la
sección ImageBitmap vs. ImageVector.
Un Painter es diferente de un DrawModifier, que dibuja estrictamente dentro de los límites que se le otorgan y no influye en la medición ni en el diseño del elemento componible.
Para crear un pintor personalizado, extiende la clase Painter e implementa el método onDraw, que permite el acceso a DrawScope para dibujar gráficos personalizados. También puedes anular intrinsicSize, que se usará para influir en el elemento de componibilidad que contiene:
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 } }
Ahora que tenemos nuestro Painter personalizado, podemos superponer cualquier imagen sobre nuestra imagen de origen de la siguiente manera:
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() )
En la siguiente figura, se muestra el resultado de la combinación de las dos imágenes con un pintor personalizado:
También se puede usar un pintor personalizado con el Modifier.paint(customPainter)
para dibujar el contenido en un elemento que admite composición de la siguiente manera:
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 **/ }
Recomendaciones para ti
- Nota: El texto del vínculo se muestra cuando JavaScript está desactivado
- ImageBitmap vs. ImageVector {:#bitmap-vs-vector}
- Gráficos en Compose
- Cómo cargar imágenes {:#loading-images}