Hemos visto en conceptos anteriores que cuando queremos mostrar una única imagen, utilizamos la función composable 'Image'. Ahora veremos como podemos mostrar imágenes dentro de un Canvas.
.Disponemos de la función drawImage que puede ser llamada dentro de Canvas.
Confeccionar una interfaz que muestre un tablero de ajedrez, disponer en su interior solo los peones blancos y negros. Recuperar las imágenes de dos archivo png.
Crearemos un proyecto llamado: 'Compose29'
La interfaz visual a implementar debe ser similar a:
El código a implementar en Kotlin para obtener dicha funcionalidad es:
package com.tutorialesprogramacionya.compose29 import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.Canvas import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Offset import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.res.imageResource import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.sp class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Column() { Row { Image( bitmap = ImageBitmap.imageResource(id = R.drawable.peonblanco), contentDescription = "" ) Image( bitmap = ImageBitmap.imageResource(id = R.drawable.peonnegro), contentDescription = "" ) Text(text = "Peones blancos y negros", fontSize = 30.sp) } TableroAjedrez() } } } } @Composable fun TableroAjedrez() { var peonBlanco = ImageBitmap.imageResource(id = R.drawable.peonblanco) var peonNegro = ImageBitmap.imageResource(id = R.drawable.peonnegro) Canvas(modifier = Modifier.fillMaxSize(), onDraw = { val ancho = size.width val alto = size.height val anchoCuadrado = if (alto > ancho) ancho / 8f else alto / 8f var columna = 0f var fila = 0f var colorActual = Color.DarkGray for (fil in 1..8) { for (col in 1..8) { drawRect( topLeft = Offset(x = columna, y = fila), size = Size(anchoCuadrado, anchoCuadrado), color = colorActual ) colorActual = if (colorActual == Color.DarkGray) Color.LightGray else Color.DarkGray if (fil == 2) drawImage( image = peonBlanco, dstOffset = IntOffset(columna.toInt(), fila.toInt()), dstSize = IntSize(anchoCuadrado.toInt(), anchoCuadrado.toInt()) ) if (fil == 7) drawImage( image = peonNegro, dstOffset = IntOffset(columna.toInt(), fila.toInt()), dstSize = IntSize(anchoCuadrado.toInt(), anchoCuadrado.toInt()) ) columna += anchoCuadrado } fila += anchoCuadrado columna = 0f colorActual = if (colorActual == Color.DarkGray) Color.LightGray else Color.DarkGray } }) }
En la parte superior de la pantalla recordamos como mostrar imágenes empleando la función componible Image, luego llamamos a la función componible TableroAjedrez:
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Column() { Row { Image( bitmap = ImageBitmap.imageResource(id = R.drawable.peonblanco), contentDescription = "" ) Image( bitmap = ImageBitmap.imageResource(id = R.drawable.peonnegro), contentDescription = "" ) Text(text = "Peones blancos y negros", fontSize = 30.sp) } TableroAjedrez() } } } }
En la función TableroAjedrez procedemos a recuperar las dos imágenes llamando a la función componible 'imageResource' (tengamos en cuenta que si bien la función TableroAjedrez luego puede llamarse varias veces por el API de Compose, la misma librería administra la lectura eficiente del recurso):
fun TableroAjedrez() { var peonBlanco = ImageBitmap.imageResource(id = R.drawable.peonblanco) var peonNegro = ImageBitmap.imageResource(id = R.drawable.peonnegro)
Primero llamamos a la función Canvas, ocupando todo el espacio disponible (Modifier.fillMaxSize()), como debemos dibujar 64 rectángulos (casillas del tablero) disponemos dos for anidados y mediante la función drawRect dibujamos cada cuadrado. Para que las celdas alternen su color, empleamos la variable colorActual y dentro del for vamos alternando entre LightGray y DarkGray:
Canvas(modifier = Modifier.fillMaxSize(), onDraw = { val ancho = size.width val alto = size.height val anchoCuadrado = if (alto > ancho) ancho / 8f else alto / 8f var columna = 0f var fila = 0f var colorActual = Color.DarkGray for (fil in 1..8) { for (col in 1..8) { drawRect( topLeft = Offset(x = columna, y = fila), size = Size(anchoCuadrado, anchoCuadrado), color = colorActual ) colorActual = if (colorActual == Color.DarkGray) Color.LightGray else Color.DarkGray if (fil == 2) drawImage( image = peonBlanco, dstOffset = IntOffset(columna.toInt(), fila.toInt()), dstSize = IntSize(anchoCuadrado.toInt(), anchoCuadrado.toInt()) ) if (fil == 7) drawImage( image = peonNegro, dstOffset = IntOffset(columna.toInt(), fila.toInt()), dstSize = IntSize(anchoCuadrado.toInt(), anchoCuadrado.toInt()) ) columna += anchoCuadrado } fila += anchoCuadrado columna = 0f colorActual = if (colorActual == Color.DarkGray) Color.LightGray else Color.DarkGray } }) }
Para dibujar una imagen llamamos a la función drawImage y le pasamos como primer parámetro la referencia de la imagen a mostrar, el segundo parámetro es la columna y fila donde debe aparecer la imagen con respecto a las dimensiones del Canvas y el tercer parámetro que configuramos es el ancho y alto que debe aparecer la imagen:
drawImage( image = peonBlanco, dstOffset = IntOffset(columna.toInt(), fila.toInt()), dstSize = IntSize(anchoCuadrado.toInt(), anchoCuadrado.toInt()) )
Las imágenes de los peones deben aparecer solo en las filas 2 y 7 del tablero:
Utilizamos los contadores columna y fila para ubicar cada cuadrado del tablero y la coordenada de la imagen.
Este proyecto lo puede descargar en un zip desde este enlace: Compose29.zip