1. Antes de comenzar
En este codelab, aprenderás a crear una lista desplazable en tu app con Jetpack Compose.
Trabajarás con la app de Affirmations, que muestra una lista de afirmaciones vinculadas con imágenes hermosas para aportar optimismo a tu día.
Los datos ya están allí, lo único que debes hacer es tomarlos y mostrarlos en la IU.
Requisitos previos
- Conocimientos de listas de Kotlin
- Experiencia en el diseño de diseños con Jetpack Compose
- Experiencia en la ejecución de apps en un dispositivo o emulador
Qué aprenderás
- Cómo crear una tarjeta de Material Design con Jetpack Compose
- Cómo crear una lista desplazable con Jetpack Compose
Qué compilarás
- Tomarás una aplicación existente y agregarás una lista desplazable a la IU.
El producto terminado se verá de la siguiente manera:
Requisitos
- Una computadora con acceso a Internet, un navegador web y Android Studio
- Acceso a GitHub
Descarga el código de inicio
En Android Studio, abre la carpeta basic-android-kotlin-compose-training-affirmations
.
- Navega a la página de repositorio de GitHub del proyecto.
- Verifica que el nombre de la rama coincida con el especificado en el codelab. Por ejemplo, en la siguiente captura de pantalla, el nombre de la rama es main.
- En la página de GitHub de este proyecto, haz clic en el botón Code, el cual abre una ventana emergente.
- En la ventana emergente, haz clic en el botón Download ZIP para guardar el proyecto en tu computadora. Espera a que se complete la descarga.
- Ubica el archivo en tu computadora (probablemente en la carpeta Descargas).
- Haz doble clic en el archivo ZIP para descomprimirlo. Se creará una carpeta nueva con los archivos del proyecto.
Abre el proyecto en Android Studio
- Inicia Android Studio.
- En la ventana Welcome to Android Studio, haz clic en Open.
Nota: Si Android Studio ya está abierto, selecciona la opción de menú File > Open.
- En el navegador de archivos, ve hasta donde se encuentra la carpeta de proyecto descomprimido (probablemente en Descargas).
- Haz doble clic en la carpeta del proyecto.
- Espera a que Android Studio abra el proyecto.
- Haz clic en el botón Run
para compilar y ejecutar la app. Asegúrate de que funcione como se espera.
2. Mira el video con instrucciones para compilar (opcional)
Si quieres ver cómo uno de los instructores del curso completa el codelab, reproduce el siguiente video.
Se recomienda expandir el video a pantalla completa (con el ícono en la esquina inferior derecha del video) para que puedas ver Android Studio y el código con mayor claridad.
Este paso es opcional. También puedes omitir el video y comenzar con las instrucciones del codelab de inmediato.
3. Crea una clase de datos de elemento de lista
Cómo crear una clase de datos para una Affirmation
En las apps para Android, las listas se componen de elementos de lista. Para datos individuales, esto podría ser algo simple, como una string o un número entero. Para los elementos de lista que tienen varios datos, como una imagen y texto, necesitarás una clase que contenga todas estas propiedades. Las clases de datos son un tipo de clase que solo contiene propiedades y pueden proporcionar algunos métodos de utilidad para trabajar con esas propiedades.
- Crea un paquete nuevo en com.example.affirmations.
Asígnele el nombre model. El paquete de modelos contendrá el modelo de datos que representará una clase de datos. Esa clase de datos se compone de propiedades que representan la información relevante a lo que será una "afirmación", que constará de un recurso de string y un recurso de imagen. Los paquetes son directorios que contienen clases e incluso otros directorios.
- Crea una clase nueva en el paquete com.example.affirmations.model.
Asígnele el nombre Affirmation a la nueva clase y conviértala en Data Class.
- Cada
Affirmation
consiste en una imagen y una string. Crea dos propiedadesval
en la clase de datosAffirmation
. Uno debe llamarsestringResourceId
y el otroimageResourceId
. Ambos deben ser números enteros.
Affirmation.kt
data class Affirmation(
val stringResourceId: Int,
val imageResourceId: Int
)
- Etiqueta la propiedad
stringResourceId
con la anotación@StringRes
y la etiquetaimageResourceId
con@DrawableRes
.stringResourceId
representa un ID para el texto de afirmación almacenado en un recurso de strings.imageResourceId
representa un ID para la imagen de afirmación almacenada en un recurso de elemento de diseño.
Affirmation.kt
data class Affirmation(
@StringRes val stringResourceId: Int,
@DrawableRes val imageResourceId: Int
)
- Ahora, abre el archivo
Datasource.kt
en el paquete com.example.affirmations.data y quita los comentarios de la claseDatasource
.
Datasource.kt
class Datasource() {
fun loadAffirmations(): List<Affirmation> {
return listOf<Affirmation>(
Affirmation(R.string.affirmation1, R.drawable.image1),
Affirmation(R.string.affirmation2, R.drawable.image2),
Affirmation(R.string.affirmation3, R.drawable.image3),
Affirmation(R.string.affirmation4, R.drawable.image4),
Affirmation(R.string.affirmation5, R.drawable.image5),
Affirmation(R.string.affirmation6, R.drawable.image6),
Affirmation(R.string.affirmation7, R.drawable.image7),
Affirmation(R.string.affirmation8, R.drawable.image8),
Affirmation(R.string.affirmation9, R.drawable.image9),
Affirmation(R.string.affirmation10, R.drawable.image10))
}
}
4. Agrega una lista a tu app
Crea una tarjeta de elemento de lista
Esta app está diseñada para mostrar una lista de afirmaciones. El primer paso para configurar la IU a fin de mostrar una lista es crear un elemento de lista. Cada elemento de afirmación consta de una imagen y una string. Los datos para cada uno de estos elementos vienen con el código de inicio, y crearás el componente de IU para mostrar ese elemento.
El elemento se compone de un elemento Card
componible y que contiene un elemento Image
y uno Text
. En Compose, un Card
es una superficie que muestra contenido y acciones en un solo contenedor. La tarjeta de Affirmation se verá de la siguiente manera:
La tarjeta muestra una imagen con un poco de texto debajo. Este diseño vertical se puede lograr usando un elemento componible Column
en un elemento Card
. Puedes probarlo tú mismo o seguir los pasos a continuación para lograrlo.
- Abre el archivo MainActivity.kt.
- Crea un método nuevo debajo del método
AffirmationApp()
, llamadoAffirmationCard()
, y anótalo con la anotación@Composable
.
MainActivity.kt
@Composable
fun AffirmationApp() {
AffirmationsTheme {
}
}
@Composable
fun AffirmationCard() {
}
- Edita la firma del método para tomar un objeto
Affirmation
como parámetro. El objetoAffirmation
proviene del paquetemodel
.
MainActivity.kt
@Composable
fun AffirmationCard(affirmation: Affirmation) {
}
- Agrega un parámetro
modifier
a la firma. Establece un valor predeterminado deModifier
para el parámetro.
MainActivity.kt
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
}
- Dentro del método
AffirmationCard
, llama al elemento componibleCard
. Pasa los siguientes parámetros:modifier
yelevation
. Pasa un objetoModifier
con el atributopadding
configurado como8.dp
para el parámetromodifier
. Pasa un valor de4.dp
paraelevation
. La propiedadelevation
se trata en detalle más adelante.
MainActivity.kt
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
Card(modifier = modifier.padding(8.dp), elevation = 4.dp) {
}
}
- Agrega un elemento
Column
componible dentro del elementoCard
. Los elementos dentro de un elementoColumn
componible se organizan automáticamente en la IU. Esto te permite colocar una imagen sobre el texto asociado. Por el contrario, un elementoRow
componible organiza los elementos contenidos de manera horizontal.
MainActivity.kt
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
Card(modifier = modifier.padding(8.dp), elevation = 4.dp) {
Column {
}
}
}
- Agrega un elemento
Image
componible dentro del cuerpo de lambda del elementoColumn
. Recuerda que un elementoImage
componible requiere un recurso para mostrarse y unacontentDescription
. El recurso debe ser unpainterResource
que se pase al parámetropainter
. El métodopainterResource
cargará elementos de diseño vectoriales o formatos de elementos de trama, como PNG. Además, pasa un elementostringResource
para el parámetrocontentDescription
.
MainActivity.kt
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
Card(modifier = modifier.padding(8.dp), elevation = 4.dp) {
Column {
Image(
painter = painterResource(affirmation.imageResourceId),
contentDescription = stringResource(affirmation.stringResourceId)
)
}
}
}
- Además de los parámetros
painter
ycontentDescription
, pasa unamodifier
y unacontentScale
. UnacontentScale
determina cómo se debe escalar y mostrar la imagen. El objetoModifier
debe tener establecido el atributofillMaxWidth
y una altura de194.dp
. ElcontentScale
debe serContentScale.Crop
.
MainActivity.kt
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
Card(modifier = modifier.padding(8.dp), elevation = 4.dp) {
Column {
Image(
painter = painterResource(affirmation.imageResourceId),
contentDescription = stringResource(affirmation.stringResourceId),
modifier = Modifier
.fillMaxWidth()
.height(194.dp),
contentScale = ContentScale.Crop
)
}
}
}
- Dentro del
Column
, crea un elementoText
componible después del elementoImage
. Pasa un elementostringResource
deaffirmation.stringResourceId
al parámetrotext
, pasa un elementoModifier
con el atributopadding
que se establece en16.dp
y establece un tema de texto pasandoMaterialTheme.typography.h6
al parámetrostyle
.
MainActivity.kt
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
Card(modifier = modifier.padding(8.dp), elevation = 4.dp) {
Column {
Image(
painter = painterResource(affirmation.imageResourceId),
contentDescription = stringResource(affirmation.stringResourceId),
modifier = Modifier
.fillMaxWidth()
.height(194.dp),
contentScale = ContentScale.Crop
)
Text(
text = stringResource(affirmation.stringResourceId),
modifier = Modifier.padding(16.dp),
style = MaterialTheme.typography.h6
)
}
}
}
Obtén una vista previa del elemento componible AffirmationCard
La tarjeta es el núcleo de la IU de la app de Affirmations, y te esforzaste por crearla. Para comprobar que la tarjeta se vea bien, puedes crear un elemento componible para obtener una vista previa sin tener que iniciar toda la app.
- Crea un método privado llamado
AffirmationCardPreview()
. Anota el método con@Preview
y@Composable
.
MainActivity.kt
@Preview
@Composable
private fun AffirmationCardPreview() {
}
- Dentro del método, llama al elemento componible
AffirmationCard
y pásale un nuevo objetoAffirmation
con el recurso de cadenasR.string.affirmation1
y el recurso de elementos de diseñoR.drawable.image1
que se pasó a su constructor.
MainActivity.kt
@Preview
@Composable
private fun AffirmationCardPreview() {
AffirmationCard(Affirmation(R.string.affirmation1, R.drawable.image1))
}
- Abre la pestaña Split y obtendrás una vista previa de
AffirmationCard
. Si es necesario, haz clic en Build & Refresh en el panel Design para mostrar la vista previa.
Cómo crear la lista
El componente del elemento de lista es el componente fundamental de la lista. Una vez que se crea el elemento de la lista, puedes aprovecharlo para crear el componente de la lista.
- Crea una función llamada
AffirmationList()
, anótala con la anotación@Composable
y declara unList
de objetosAffirmation
como parámetro en la firma del método.
MainActivity.kt
@Composable
private fun AffirmationList(affirmationList: List<Affirmation>) {
}
- Declara un objeto
modifier
como parámetro en la firma del método con un valor predeterminado deModifier
.
MainActivity.kt
@Composable
private fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
}
- En Jetpack Compose, se puede crear una lista desplazable con el elemento componible
LazyColumn
. La diferencia entre un elementoLazyColumn
y un objetoColumn
es que debe usarse un objetoColumn
cuando tienes una pequeña cantidad de elementos para mostrar, ya que Compose los carga todos a la vez. UnColumn
solo puede contener una cantidad predefinida o fija de elementos componibles. Un elementoLazyColumn
puede agregar contenido a pedido, lo que lo hace útil para listas largas y, en especial, cuando se desconoce la longitud de la lista. UnLazyColumn
también proporciona desplazamiento de manera predeterminada, sin código adicional. Declara un elementoLazyColumn
componible dentro de la funciónAffirmationList()
.
MainActivity.kt
@Composable
private fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
LazyColumn {
}
}
- En el cuerpo de lambda de
LazyColumn
, llama al métodoitems()
y pasaaffirmationList
. El métodoitems()
es la manera en la que agregas elementos aLazyColumn
. Este método es algo único de ese elemento y no se suele usar para la mayoría de los elementos componibles.
MainActivity.kt
@Composable
private fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
LazyColumn {
items(affirmationList){
}
}
}
- Una llamada al método
items()
requiere una función lambda. En esa función, especifica un parámetro deaffirmation
que represente un elemento de afirmación deaffirmationList
.
MainActivity.kt
@Composable
private fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
LazyColumn {
items(affirmationList){ affirmation ->
}
}
}
- Para cada afirmación de la lista, llama al elemento componible
AffirmationCard()
y pásale laaffirmation
.
MainActivity.kt
@Composable
private fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
LazyColumn {
items(affirmationList){ affirmation ->
AffirmationCard(affirmation)
}
}
}
Mostrar la lista
- En la expresión lambda, llama al elemento componible
AffirmationList
y pasaDataSource().loadAffirmations()
al parámetroaffirmationList
.
MainActivity.kt
@Composable
fun AffirmationApp() {
AffirmationsTheme {
AffirmationList(affirmationList = Datasource().loadAffirmations())
}
}
Ejecuta la app de Affirmations en un dispositivo o emulador y mira el producto terminado.
5. Obtén el código de la solución
Para descargar el código del codelab terminado, puedes usar estos comandos de git:
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-affirmations.git $ cd basic-android-kotlin-compose-training-affirmations $ git checkout main
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.
6. Conclusión
Ahora sabes cómo crear tarjetas, elementos de lista y listas desplazables con Jetpack Compose. Ten en cuenta que estas son solo herramientas básicas para crear una lista. Puedes darle rienda suelta a tu creatividad y personalizar los elementos de la lista como quieras.
Resumen
- Usa elementos componibles
Card
para crear elementos de lista. - Modifica la IU que contiene un elemento
Card
componible. - Crea una lista desplazable con el elemento
LazyColumn
componible. - Crear una lista con elementos de una lista personalizada