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