1. Antes de comenzar
En este codelab, aprenderás a agregar imágenes a tu app con un elemento Image
que admite composición.
Requisitos previos
- Conocimientos básicos sobre cómo crear y ejecutar una app en Android Studio.
- Conocimientos básicos sobre cómo agregar elementos de la IU, por ejemplo, elementos de texto que admiten composición.
Qué aprenderás
- Cómo agregar una imagen o foto a tu app para Android
- Cómo mostrar una imagen en tu app con un elemento
Image
componible. - Prácticas recomendadas para usar los recursos de
String
.
Qué compilarás
- Mejorarás la app de Happy Birthday para que incluya una imagen.
Requisitos
- Una computadora con Android Studio instalado
- La app del codelab Cómo compilar una app simple con elementos de texto que admiten composición
2. Configura la app
Abre tu proyecto de Happy Birthday del codelab anterior en Android Studio.
Cuando ejecutes la app, debería verse como esta captura de pantalla.
Cómo agregar una imagen a tu proyecto
En esta tarea, descargarás una imagen de Internet y la agregarás a la app de Happy Birthday.
- Abre la imagen de la app de tarjeta de cumpleaños desde este vínculo.
- Haz clic en Download.
- Haz clic con el botón derecho en la imagen y, luego, guarda el archivo en tu computadora como
androidparty.png
. - Toma nota de dónde guardaste la imagen.
Por ejemplo, es posible que la hayas guardado en la carpeta Descargas.
- En Android Studio, haz clic en View > Tool Windows > Resource Manager o en la pestaña Resource Manager junto a la ventana Project.
- Haz clic en + (Add resources to the module) > Import Drawables.
- En el navegador de archivos, selecciona el archivo de imagen que descargaste y haz clic en Open.
Se abrirá el diálogo Import Drawables.
- Android Studio te muestra una vista previa de la imagen. Selecciona Density en la lista desplegable QUALIFIER TYPE. En una sección posterior, aprenderás por qué lo haces.
- Selecciona No Density en la lista VALUE.
Los dispositivos Android están disponibles en diferentes tamaños de pantalla (teléfonos, tablets y TVs, etc.), y sus pantallas también tienen píxeles de distintos tamaños. Es decir, hay dispositivos que tienen 160 píxeles por pulgada cuadrada y otros que adaptan 480 píxeles en el mismo espacio. Si no tienes en cuenta estas variaciones de densidad de píxeles, es posible que el sistema escale tus imágenes, lo que podría producir que se vean borrosas, imágenes grandes que consumen demasiada memoria o imágenes cuyo tamaño es incorrecto.
Cuando cambias el tamaño de las imágenes a uno más grande del que puede controlar el sistema Android, se genera un error de memoria insuficiente. En el caso de las imágenes de fondo o fotos, como la imagen actual, androidparty.png
, debes colocarlas en la carpeta drawable-nodpi
, ya que eso detendrá el comportamiento de cambio de tamaño.
Para obtener más información, consulta Cómo brindar compatibilidad con diferentes densidades de píxeles.
- Haz clic en Next.
- Android Studio te muestra la estructura de carpetas en la que se ubicará la imagen. Observa la carpeta
drawable-nodpi
. - Haz clic Import(C).
Android Studio crea una carpeta drawable-nodpi
y coloca la imagen en ella. En la vista de proyectos de Android Studio, el nombre del recurso se muestra como androidparty.png (nodpi)
. En el sistema de archivos de la computadora, Android Studio crearía una carpeta con el nombre drawable-nodpi
.
Si la imagen se importó correctamente, Android Studio la agregará a la lista en la pestaña Drawable. En esa lista se incluyen todos los íconos e imágenes de tu app. Ahora, puedes usar la imagen en tu app.
- Para regresar a la vista de proyectos, haz clic en View > Tool Windows > Project o en la pestaña Project del extremo izquierdo.
- Haz clic en app > res > drawable para confirmar que la imagen se encuentra en la carpeta
drawable
.
3. Cómo agregar un elemento Image que admite composición
Para mostrar una imagen en tu app, es necesario mostrar un lugar. Así como usas un elemento Text
componible para mostrar texto, puedes usar un elemento Image
componible para mostrar una imagen.
En esta tarea, agregarás un elemento Image
componible a tu app, configurarás su imagen en la imagen que descargaste, la posicionarás y ajustarás su tamaño para que ocupe toda la pantalla.
Cómo agregar una función de componibilidad para agregar una imagen
- En el archivo
MainActivity.kt
, agrega una función de componibilidadGreetingImage()
después de la funciónGreetingText()
. - Pasa la función
GreetingImage()
a dos parámetrosString
: uno con el nombremessage
para el saludo de cumpleaños y el otro con el nombrefrom
para la firma.
@Composable
fun GreetingImage(message: String, from: String) {
}
- Cada función de componibilidad debe aceptar un parámetro
Modifier
opcional. Los modificadores le indican a un elemento de la IU cómo aparecer o comportarse en su diseño de nivel superior. Agrega otro parámetro al elementoGreetingImage()
componible.
@Composable
fun GreetingImage(message: String, from: String, modifier: Modifier = Modifier) {
}
Recursos en Jetpack Compose
Los recursos son los archivos adicionales y el contenido estático que usa tu código, como mapas de bits, strings de interfaz de usuario, instrucciones de animación, etc. Para obtener más información sobre los recursos en Android, consulta Información general sobre los recursos de las app.
Siempre debes separar los recursos para apps, como imágenes y strings, de tu código para que puedas mantenerlos de forma independiente. En tiempo de ejecución, Android utiliza el recurso adecuado según la configuración actual. Por ejemplo, puedes proporcionar un diseño de interfaz de la IU diferente según el tamaño de la pantalla o strings diferentes según la configuración de idioma.
Cómo agrupar recursos
Siempre debes colocar cada tipo de recurso en un subdirectorio específico del directorio res/
de tu proyecto. Por ejemplo, esta es la jerarquía de archivos de un proyecto simple:
MyProject/
src/
MyActivity.kt
res/
drawable/
graphic.png
mipmap/
icon.png
values/
strings.xml
Como se ve en este ejemplo, el directorio res/
contiene todos los recursos de los subdirectorios, que incluyen un directorio drawable/
para un recurso de imagen, un directorio mipmap/
para los íconos de selector y un directorio values/
para recursos de strings. Para obtener más información sobre el uso, el formato y la sintaxis para los recursos de la app, consulta Descripción general de los tipos de recursos.
Acceso a recursos
Jetpack Compose puede acceder a los recursos definidos en tu proyecto de Android. Se puede acceder a los recursos con los ID de recursos que se generan en la clase R
de tu proyecto.
Una clase R
es una clase que Android genera automáticamente y que contiene los ID de todos los recursos en el proyecto. En la mayoría de los casos, el ID del recurso es el mismo que el nombre del archivo. Por ejemplo, se puede acceder a la imagen en la jerarquía de archivos anterior con este código:
R.drawable.graphic
En la próxima tarea, usarás la imagen y el archivo androidparty.png
, que agregaste en la tarea anterior.
- En la función
GreetingImage()
, declara una propiedadval
y asígnale el nombreimage
. - Realiza una llamada a la función
painterResource()
y pasa el recursoandroidparty
. Asigna el valor que se muestra a la variableimage
.
val image = painterResource(R.drawable.androidparty)
Android Studio destaca el código .painterResource
, ya que necesitas importar la función para compilar tu app.
- Haz clic en
.painterResource
, el cual destaca Android Studio. - Haz clic en Import en la ventana emergente para agregar la importación de
androidx.compose.ui.res.painterResource
.
La función painterResource()
carga un recurso de imagen de elemento de diseño y toma el ID de recurso (en este caso, R.drawable.androidparty
) como argumento.
- Después de la llamada a la función
painterResource()
, agrega un elementoImage
componible y, luego, pasaimage
como un argumento con nombre para el elementopainter
.
Image(
painter = image
)
Android Studio destaca el código Image
, ya que debes importar la función para compilar tu app.
Para corregir esta advertencia, agrega la siguiente importación en la parte superior de tu archivo MainActivity.kt
:
import androidx.compose.foundation.Image
La advertencia inicial ya está resuelta, pero si colocas el cursor sobre la palabra Image
, Android Studio mostrará una nueva advertencia que dice: "None of the following functions can be called with the arguments provided". Esto se debe a que el argumento proporcionado no coincide con ninguna de las firmas de la función Image
.
Esta advertencia se corregirá en la siguiente sección.
Cómo verificar la accesibilidad de tu app
Cuando sigues las prácticas de codificación para la accesibilidad, permites que todos los usuarios, incluidos los que tienen discapacidades, naveguen con mayor facilidad e interactúen con esta.
Android Studio proporciona sugerencias y advertencias para ayudarte a que tu app sea más accesible. Una descripción de contenido define el propósito de un elemento de la IU, lo que permite que tu app sea más útil con TalkBack.
Sin embargo, la imagen de esta app solo se incluye con fines decorativos. Agregar una descripción de contenido para la imagen dificultaría el uso con TalkBack en este caso particular. En lugar de configurar la descripción del contenido que se anuncia al usuario, puedes establecer el argumento contentDescription
de la imagen en null
para que TalkBack omita el elemento Image
que admite composición.
- En el elemento
Image
que admite composición, agrega otro argumento con el nombrecontentDescription
y configura su valor comonull
.
Image(
painter = image,
contentDescription = null
)
Cómo obtener una vista previa de Image
componible
En esta tarea, obtienes una vista previa de la imagen componible y ejecutas la app en un emulador o dispositivo.
- En la función
BirthdayCardPreview()
, reemplaza la llamada aGreetingText()
por una aGreetingImage()
.
Tu función debería verse como este fragmento de código:
@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
HappyBirthdayTheme {
GreetingImage(
message = "Happy Birthday Sam!",
from = "From Emma"
)
}
}
- El panel Design debería actualizarse automáticamente. De lo contrario, haz clic en para compilar.
Ten en cuenta que ya no puedes ver el texto porque la función nueva solo tiene un elemento Image
componible, pero no un elemento Text
.
4. Cómo agregar un diseño de cuadros
Los tres elementos de diseño estándar básicos en Compose son los elementos Column
, Row
y Box
componibles. Aprendiste sobre los elementos Column
y Row
componibles en los codelabs anteriores, ahora explorarás más sobre el elemento Box
componible.
El diseño Box
es uno de los elementos de diseño estándar en Compose. Usa el diseño Box
para apilar elementos uno sobre el otro. El diseño Box
también te permite configurar la alineación específica de los elementos que contiene.
- En la función
GreetingImage()
, agrega un elementoBox
componible alrededor del elementoImage
componible, como se muestra a continuación:
@Composable
fun GreetingImage(message: String, from: String, modifier: Modifier = Modifier) {
val image = painterResource(R.drawable.androidparty)
Box {
Image(
painter = image,
contentDescription = null
)
}
}
- Importa la función
androidx.compose.foundation.layout.Box
cuando Android Studio lo solicite. - Agrega código para pasar el parámetro
modifier
al elemento componibleBox
.
@Composable
fun GreetingImage(message: String, from: String, modifier: Modifier = Modifier) {
val image = painterResource(R.drawable.androidparty)
Box(modifier) {
Image(
painter = image,
contentDescription = null
)
}
}
- Al final del elemento componible
Box
, llama a la funciónGreetingText()
y pasa el mensaje de cumpleaños y la firma, como se muestra a continuación:
@Composable
fun GreetingImage(message: String, from: String, modifier: Modifier = Modifier) {
val image = painterResource(R.drawable.androidparty)
Box(modifier) {
Image(
painter = image,
contentDescription = null
)
GreetingText(
message = message,
from = from,
modifier = Modifier
.fillMaxSize()
.padding(8.dp)
)
}
}
- Observa la vista previa actualizada en el panel Design.
Deberías ver el texto y la imagen.
- Para que los cambios anteriores se reflejen en el emulador o en un dispositivo, en la función
onCreate()
, reemplaza la llamada a la funciónGreetingText()
por una aGreetingImage()
.
Tu bloque setContent
debería verse como este fragmento de código:
setContent {
HappyBirthdayTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
GreetingImage(
message = "Happy Birthday Sam!",
from = "From Emma"
)
}
}
}
Observa que la imagen es tan ancha como la pantalla, pero está anclada en la parte superior de la pantalla. Hay espacio en blanco en la parte inferior de la pantalla que no luce muy atractivo. En la próxima tarea, completarás el ancho y la altura de la pantalla, y ajustarás la escala de la imagen de modo que la ocupe en su totalidad.
5. Cambia la opacidad y ajusta la imagen
En esta tarea, lograrás que la imagen se muestre en pantalla completa para embellecer tu app. Para ello, usa los parámetros ContentScale
.
Cómo ajustar la escala del contenido
Agregaste la imagen a tu app y la posicionaste. Ahora debes ajustar el tipo de escala de la imagen, que indica cómo ajustar el tamaño de la imagen para que se muestre en pantalla completa.
Hay bastantes tipos de ContentScale
disponibles. Usa el escalamiento del parámetro ContentScale.Crop
, que ajusta la escala de la imagen de manera uniforme para mantener la relación de aspecto, de modo que el ancho y el alto de esta sean iguales o mayores a la dimensión correspondiente de la pantalla.
- Agrega un argumento
ContentScale
con nombre a la imagen.
Image(
painter = image,
contentDescription = null,
contentScale = ContentScale.Crop
)
- Importa la interfaz
androidx.compose.ui.layout.ContentScale
cuando Android Studio lo solicite. - Consulta el panel Design.
La imagen debería ocupar toda la pantalla en la vista previa, como se muestra en esta captura de pantalla:
Cambia la opacidad
Para mejorar el contraste de la app, cambia la opacidad de la imagen de fondo.
Agrega el parámetro alpha
al elemento componible Image
y establécelo en 0.5F
.
Image(
painter = image,
contentDescription = null,
contentScale = ContentScale.Crop,
alpha = 0.5F
)
Observa el cambio en la opacidad de la imagen.
Hay mucho código. Es momento de obtener una vista previa de todo tu arduo trabajo.
Ejecuta la app
Ejecuta la app en un dispositivo o emulador.
Buen trabajo con la imagen en pantalla completa y el mensaje de texto. También cambiaste la opacidad de la imagen.
Modificadores de diseño
Los modificadores se usan para decorar o agregar comportamiento a los elementos de IU de Jetpack Compose. Por ejemplo, puedes agregar fondos, padding o comportamiento a filas, texto o botones. Para configurarlos, un elemento componible o un diseño debe aceptar un modificador como parámetro.
En un codelab anterior, aprendiste sobre los modificadores y usaste el modificador de padding (Modifier.padding
) para agregar espacio alrededor de un Text
componible. Los modificadores pueden ser muy útiles, y lo verás en este camino de aprendizaje y en los próximos.
Por ejemplo, este elemento Text
componible tiene un argumento Modifier
que cambia el color de fondo a verde.
// Example
Text(
text = "Hello, World!",
// Solid element background color
modifier = Modifier.background(color = Color.Green)
)
Al igual que en el ejemplo anterior, puedes agregar modificadores a los diseños para posicionar los elementos secundarios mediante propiedades de disposición y alineación.
Para establecer la posición de los elementos secundarios dentro de un Row
, configura los argumentos horizontalArrangement
y verticalAlignment
. Para una Column
, configura los argumentos verticalArrangement
y horizontalAlignment
.
La propiedad de las disposiciones se usa para organizar los elementos secundarios cuando el tamaño del diseño es mayor que la suma de sus elementos secundarios.
Por ejemplo: cuando el tamaño de Column
es mayor que la suma de sus tamaños secundarios, se puede especificar un verticalArrangement
para definir el posicionamiento de la elementos secundarios dentro de Column
. A continuación, se muestra una ilustración de diferentes disposiciones verticales:
De la misma manera, cuando el tamaño de Row
es mayor que la suma de sus tamaños secundarios, se puede especificar un horizontalArrangement
para definir el posicionamiento de la elementos secundarios dentro de Row
. A continuación, se muestra una ilustración de diferentes disposiciones horizontales:
La propiedad de alineación se usa para alinear los elementos secundarios al comienzo, en el centro o al final del diseño.
6. Alinea y ordena el texto
En esta tarea, observarás el código que agregaste en el codelab anterior para ordenar el texto en la app.
- En el archivo
MainActivity.kt
, desplázate hasta la funciónGreetingText()
. La propiedadverticalArrangement
de la columna se establece enArrangement.Center
. De este modo, el contenido de texto se centrará en la pantalla.
@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
Column(
verticalArrangement = Arrangement.Center,
modifier = modifier
) {
Text(
text = message,
fontSize = 100.sp,
lineHeight = 116.sp,
textAlign = TextAlign.Center
)
Text(
text = from,
fontSize = 36.sp,
modifier = Modifier
.padding(16.dp)
.align(alignment = Alignment.End)
)
}
}
Padding
Un elemento de la IU se une a su contenido. Para evitar que la contracción sea demasiado marcada, puedes especificar una cantidad de padding a cada lado.
El padding se usa como modificador, lo que significa que puedes aplicarlo a cualquier elemento componible. Para cada lado del elemento componible, el modificador padding
toma un argumento opcional que define la cantidad de padding.
// This is an example.
Modifier.padding(
start = 16.dp,
top = 16.dp,
end = 16.dp,
bottom = 16.dp
)
- ¡Tu turno! En el archivo
MainActivity.kt
, desplázate hasta la ubicación en la que se llama a la funciónGreetingText()
y observa el atributo de padding.
modifier = Modifier
.fillMaxSize()
.padding(8.dp)
- De manera similar, dentro de la función
GreetingText()
, observa el padding para la firmaText
componible.
modifier = Modifier
.padding(16.dp)
.align(alignment = Alignment.End)
7. Cómo implementar prácticas recomendadas de código
Traducción
A la hora de escribir apps, es importante recordar que podrían traducirse a otro idioma. Como aprendiste en un codelab anterior, un tipo de datos String
es una secuencia de caracteres, como "Happy Birthday Sam!"
.
Una string codificada es una que se escribe directamente en el código de tu app. Las strings codificadas hacen que sea más difícil traducir tu app a otros idiomas y dificultan la reutilización de una string en diferentes lugares de la app. Puedes extraer strings en un archivo de recursos para resolver estos problemas. En lugar de codificar strings en tu código, colócalas en un archivo, asígnales un nombre a los recursos de strings y usa los nombres cuando desees usar las strings. El nombre seguirá siendo el mismo, incluso si cambias la string o la traduces a otro idioma.
- En el archivo
MainActivity.kt
, desplázate hasta la funciónonCreate()
. Selecciona el saludo de cumpleaños, la cadenaHappy Birthday Sam!
sin comillas. - En la parte izquierda de la pantalla, haz clic en la bombilla.
- Selecciona Extract string resource.
Android Studio abrirá el diálogo Extract Resource. En él, podrás personalizar cómo se llamará tu recurso de strings y algunos detalles sobre cómo almacenarlo. En el campo Resource name, introduce el nombre que le asignarás a la string. En el campo Resource Value, se introduce la string real.
- En el diálogo Extract Resource, cambia Resource name por
happy_birthday_text
.
Los recursos de strings deben tener nombres en minúscula y, si hay más de una palabra, estas deben estar separadas por un guión bajo. Deja las otras opciones de configuración con sus valores predeterminados.
- Haz clic en OK.
- Observa los cambios en el código.
La string codificada ahora se reemplaza por una llamada a la función getString()
.
GreetingImage(
message = getString(R.string.happy_birthday_text),
from = "From Emma",
modifier = Modifier.padding(8.dp)
)
- En el panel Project, abre el archivo strings.xml de la ruta
app > res > values > strings.xml
y observa que Android Studio creó un recurso de cadenas con el nombrehappy_birthday_text
.
<resources>
<string name="app_name">Happy Birthday</string>
<string name="happy_birthday_text">Happy Birthday Sam!</string>
</resources>
El archivo strings.xml
tiene una lista de cadenas que el usuario verá en la app. Ten en cuenta que el nombre de tu app también es un recurso de cadenas. Si colocas todas las strings en un solo lugar, podrás traducir de manera sencilla todo el texto de tu app y volver a usar más fácilmente una string en diferentes partes de tu app.
- Sigue los mismos pasos para extraer el texto de la firma
Text
que admite composición, pero esta vez introducesignature_text
en el campo Resource name.
El archivo finalizado debería verse de la siguiente manera en el fragmento de código:
<resources>
<string name="app_name">Happy Birthday</string>
<string name="happy_birthday_text">Happy Birthday Sam!</string>
<string name="signature_text">From Emma</string>
</resources>
- Actualiza
BirthdayCardPreview()
para usarstringResource()
y las cadenas extraídas.
@Preview(showBackground = true)
@Composable
fun BirthdayCardPreview() {
HappyBirthdayTheme {
GreetingImage(
message = stringResource(R.string.happy_birthday_text),
from = stringResource(R.string.signature_text)
)
}
}
- Vuelve a ejecutar la app para asegurarte de que siga funcionando correctamente.
8. Prueba este desafío
¡Bien hecho! Agregaste la imagen a la app. Este es un desafío para ti:
- Ordena o alinea el texto componible de la firma de modo que se alinee al centro de la pantalla.
La app debería verse de la siguiente manera:
Este es el código de la solución de la función GreetingText()
para que lo consultes:
@Composable
fun GreetingText(message: String, from: String, modifier: Modifier = Modifier) {
Column(
verticalArrangement = Arrangement.Center,
modifier = modifier
) {
Text(
text = message,
fontSize = 100.sp,
lineHeight = 116.sp,
textAlign = TextAlign.Center
)
Text(
text = from,
fontSize = 36.sp,
modifier = Modifier
.padding(16.dp)
.align(alignment = Alignment.CenterHorizontally)
)
}
}
9. Cómo obtener el código de la solución
El código de la solución de la app de Happy Birthday está en GitHub.
GitHub es un servicio que permite que los desarrolladores administren el código de sus proyectos de software. Utiliza Git, un sistema de control de versión que realiza un seguimiento de los cambios realizados para cada versión del código. Si alguna vez viste el historial de versiones de un documento en Documentos de Google, puedes consultar cuándo y qué cambios se realizaron en el pasado. Del mismo modo, puedes realizar un seguimiento del historial de versiones del código de un proyecto. Esto es útil cuando trabajas en un proyecto de forma individual o con un equipo.
GitHub también tiene un sitio web que te permite ver y administrar tu proyecto. Este vínculo de GitHub te permite explorar en línea los archivos del proyecto de Happy Birthday o descargarlos en tu computadora.
Para descargar el código del codelab terminado, puedes usar este comando de git:
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-birthday-card-app.git
También puedes descargar el repositorio como un archivo ZIP, descomprimirlo y abrirlo en Android Studio.
Si deseas ver el código de la solución, puedes hacerlo en GitHub.
Ramas en GitHub
Antes de comprender qué es una rama, entiende qué es un repositorio o un repo. Un repositorio es el proyecto completo (directorios y archivos) que clonas (copias) en tu computadora. Una rama es una versión de tu repositorio o, en otras palabras, una línea de desarrollo independiente. Por ejemplo, en este curso, la rama starter podría ser una versión de un proyecto que usaste para compilar durante el codelab. La rama main o solution es la versión de tu proyecto al final del codelab, que contiene el código completo de la solución.
Un repositorio puede contener varias ramas, lo que significa que hay varias versiones del código en el repositorio.
10. Conclusión
Agregaste una imagen a tu app de Happy Birthday, alineaste el texto con modificadores, según los lineamientos de accesibilidad, y facilitaste la traducción a otros idiomas. Lo más importante es que terminaste de crear tu propia app de Happy Birthday. Comparte tu trabajo en las redes sociales y usa el hashtag #AndroidBasics para que podamos verlo.
Resumen
- La pestaña Resource Manager de Android Studio te permite agregar y organizar tus imágenes y otros recursos.
- Un elemento
Image
componible es un elemento de la IU que muestra imágenes en tu app. - Un elemento
Image
componible debe tener una descripción de contenido para facilitar la accesibilidad en tu app. - El texto que se muestra al usuario, como el saludo de cumpleaños, debe extraerse en un recurso de strings para que sea más fácil traducir la app a otros idiomas.