Cargar imágenes e iconos en Jetpack Compose
Antonio Leiva

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 nos va a ofrecer un painter 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:1.3.2")

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 un rememberImagePainter() y pasarle la URL:

Image(
    painter = rememberImagePainter("https://lorempixel.com/400/400/people/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:

painter = rememberImagePainter(
    data = "https://lorempixel.com/400/400/people/1/",
    builder = {
        transformations(CircleCropTransformation())
    }),

Existen varias transformaciones más, como GrayScaleTransformation, BlurTransformation o 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:

builder = {
    crossfade(true)
}

Pero volviendo a nuestro objetivo inicial, realmente lo que queremos es que la imagen ocupe todo el espacio disponible. el modifier viene a nuestro rescater.

Si tienes dudas sobre cómo funcionan los Modifiers, tengo un artículo entero hablando sobre ello.

Image(
    painter = rememberImagePainter(
        data = "https://lorempixel.com/400/400/people/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:

Image(
    painter = rememberImagePainter(
        data = "https://lorempixel.com/400/400/people/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.

Quizá también te interese…

Navegación en Jetpack Compose con Navigation Compose

Navegación en Jetpack Compose con Navigation Compose

Jetpack Compose es un cambio de paradigma enorme en muchos aspectos. Cambia la forma de pensar en casi todos los puntos involucrados en el desarrollo de una App Android. Y la navegación no iba a ser menos. ¿Cómo se navega en Jetpack Compose? ¿Qué opciones tenemos?...

5 consejos para estructurar el código en Jetpack Compose

5 consejos para estructurar el código en Jetpack Compose

Escribir la interfaz con código es genial, pero puede ser que pronto se nos vaya de las manos. Aunque la forma de escribir el código de Jetpack Compose es muy natural y relativamente directa, sí que es verdad que en pro de la flexibilidad, también hay algunos...

0 comentarios

Enviar un comentario

Los datos personales que proporciones a través de este formulario quedarán registrados en un fichero de Antonio Leiva Gordillo, con el fin de gestionar los comentarios que realizas en este blog. La legitimación se realiza a través del consentimiento de la parte interesada. Si no se acepta, no podrás comentar en este blog. Los datos que proporciona solo se utilizan para evitar el correo no deseado y no se usarán para nada más. Puede ejercer los derechos de acceso, rectificación, cancelación y oposición en contacto@devexperto.com.

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Acepto la política de privacidad *