Algo que vas a tener que hacer casi siempre en una App es cargar imágenes, ya sea desde un servidor remoto, o desde tu propio dispositivo.
En el sistema clásico de vistas nunca existió una forma “oficial”, y siempre hemos tenido que recurrir a librerías de terceros.
Y… ¡Oh, sorpresa! en Jetpack Compose ocurre lo mismo.
Durante un tiempo, en la librería de Accompanist, una librería donde se van añadiendo funcionalidades experimentales para Compose, se daba soporte para tres librerías: Picasso, Glide y Coil.
Pero finalmente se decidió eliminar esos adaptadores de Accompanist, y recomiendan en su lugar utilizar la integración ya incluida en la librería de Coil.
Así que en este artículo vamos a ver cómo usar Coil, y también cómo cargar iconos que nos provee la librería de Compose.
Recuerda que nuestro objetivo es conseguir algo como esto:
En el artículo anterior hemos visto cómo hacer todo usando modifiers, excepto cargar las imágenes. Así que vamos a ello:

¡Atención! Si quieres acceder más rápido a todo el contenido en vídeo, organizado, con contenido extra, soporte y muchas más sorpresas, puedes apuntarte gratis a mi formación Compose Expert y ver gratis el primer módulo de más de 3 horas con todo lo necesario para empezar.
Cargar imágenes con Coil
El Composable
que nos permite cargar imágenes tiene un nombre bien sencillo: Image
Tenemos varias formas de cargar una imagen, por ejemplo a partir de un bitmap, pero la más habitual será la de usar un painter
.
El painter
define lo que hay que pintar en la Image
. La librería de Coil va más allá y nos ofrece su propia variante de Image
llamada AsyncImage
, que de forma muy sencilla nos permitirá cargar imágenes.
En la documentacion para usar Coil en Jetpack Compose se nos indica que lo primero que tenemos que hacer es añadir una dependencia:
implementation 'io.coil-kt:coil-compose:2.0.0'
Tampoco te olvides de añadir el permiso de Internet en el AndroidManifest
:
<uses-permission android:name="android.permission.INTERNET"/>
Para cargar una imagen, tan solo hay que usar una AsyncImage
y pasarle la URL por el parámetro model
:
AsyncImage( model = "https://loremflickr.com/400/400/cat?lock=1", contentDescription = null, )
El contentDescription
es para temas de accesibilidad, y deberían ser un texto que indique lo que muestra la imagen. De momento, y por simplificar, lo vamos a dejar a null
.
Tendrás que ejecutar en el dispositivo, ya que las imágenes de red no las carga la preview. El resultado será este:
Esto lo conseguirás si has aplicado todos los pasos de artículos anteriores, y especialmente lo que vimos en el de layouts en Jetpack Compose, y añades la imagen en el Box
al que pusimos el fondo rojo. Aquí ya se lo he quitado.
Imagina que quieres transformar la imagen y hacerla circular. Para ello, puedes aplicar una transformation
. Necesitarás usar el builder de ImageRequest
:
AsyncImage( model = ImageRequest.Builder(LocalContext.current) .data("https://loremflickr.com/400/400/cat?lock=1") .transformations(CircleCropTransformation()) .build(), contentDescription = null, modifier = Modifier.clip(CircleShape) )
Existen alguna transformación más, como RoundedCornersTransformation
. Y por supuesto, puedes crearte las tuyas propias.
Se pueden definir muchas más cosas en ese builder
, pero por ejemplo una interesante es la transición. Puedes hacer un efecto de crossfade para cuando cargue:
model = ImageRequest.Builder(LocalContext.current) .data("https://loremflickr.com/400/400/cat?lock=1") .transformations(CircleCropTransformation()) .crossfade(true) .build(),
Pero volviendo a nuestro objetivo inicial, realmente lo que queremos es que la imagen ocupe todo el espacio disponible. el modifier
viene a nuestro rescate.
Si tienes dudas sobre cómo funcionan los Modifier
s, tengo un artículo entero hablando sobre ello.
AsyncImage( model = "https://loremflickr.com/400/400/cat?lock=1", contentDescription = null, modifier = Modifier.fillMaxSize(), )
Pero esto no es suficiente, ya que si te fijas, la imagen mantiene unas dimensiones que permitan que se vea entera:
Lo que queremos es que ocupe el espacio disponible. Para ello, tenemos el argumento contentScale
, que sería el equivalente al scaleType
del sistema de vistas original. Podemos usar el Crop
:
AsyncImage( model = "https://loremflickr.com/400/400/cat?lock=1", contentDescription = null, modifier = Modifier.fillMaxSize(), contentScale = ContentScale.Crop )
¡Ya lo tenemos!
Cargar iconos de la librería de Material
Ahora que tenemos esta imagen cargada, necesitamos mostrar un icono encima.
Vamos a representar que tenemos fotos y vídeos, y el vídeo tendrá que llevar un icono de play.
Para ello, vamos a usar los iconos que nos provee Jetpack Compose. El componente que necesitamos usar es Icon
:
Icon( Icons.Default.PlayArrow, contentDescription = null, modifier = Modifier.size(92.dp) )
Estamos cargando un icono de “Play” con un tamaño de 92dp:
Si te fijas, estamos usando Icons.Default
. Existen distintos estilos de iconos:
- Filled (es el Default)
- Outlined
- Rounded
- TwoTone
- Sharp
Puedes usar el estilo que más te interese para tu app particular.
Nos faltan 3 cosas:
Cambiar el color de un icono
Para ello, el Icon
tiene un atributo tint
. Vamos a ponerlo blanco:
Icon( Icons.Default.PlayArrow, contentDescription = null, modifier = Modifier.size(92.dp), tint = Color.White )
El icono no se corresponde
La realidad es que en Jetpack Compose solo vienen un número limitado de iconos por defecto. Si quieremos añadir más, tenemos que incluir esta librería:
implementation "androidx.compose.material:material-icons-extended:$compose_version"
Ahora ya podemos seleccionar PlayCircleOutline
:
Icon( Icons.Default.PlayCircleOutline, contentDescription = null, modifier = Modifier.size(92.dp), tint = Color.White )
El icono no está centrado
Esto ya hemos visto cómo hacerlo anteriormente, con el modifier align
:
Icon( Icons.Default.PlayCircleOutline, contentDescription = null, modifier = Modifier .size(92.dp) .align(Alignment.Center), tint = Color.White )
Si ahora ejecutamos, tendremos el resultado que buscábamos. Es más ancho que la imagen original, pero esto solo será hasta que podamos ponerlo en un Grid que nos ajuste el ancho a lo necesario:
Cargar iconos desde resourrces
También es posible cargar drawables clásicos con otra sobrecarga del Composable Icon
que recibe un painter
. También podríamos cargarlo en un Image
.
Para ello solo habría que usar este painter:
painter = painterResource(id = R.drawable.my_resource)
Con esto ya tenemos todo lo necesario para cargar las imágenes, los textos, e incluso mostrar el icono de vídeo si toca, pero aún no hemos hablado de cómo proveerle esa información.
Para esto es importante entender cómo funciona el estado, pero antes quiero enseñarte cómo crear una lista de elementos
Si no quieres perderte nada sobre este curso de Jetpack Compose, y además poder acceder a soporte y contenido extra, te animo a que te apuntes a mi formación gratuita:

Apúntate ahora a Compose Expert y accede a más de 3h de contenido gratuito, soporte, extras y mucho más totalmente gratis.
También puedes ver el código en el commit correspondiente del repositorio.
0 comentarios