8 - Agregar elementos a listas dinámica de datos

Hemos visto como mostrar un objeto de la clase List empleando a la función componible LazyColumn e items, veremos como trabajar con listas que mantienen el estado, para que cada vez que agreguemos un elemento a la lista, el mismo se muestre en la pantalla gracias a Compose.

Problema

Se deben disponer dos controles para el ingreso del nombre de un contacto y su mail. Al presionar un botón almacenar dichos valores en una lista con estado y mostrar todos los contactos en pantalla.

La interfaz previa a ingresar datos debe aparecer:

listas dinámicas Jetpack Compose

Luego que ingresamos varios datos se debe mostrar mediante LazyColumn cada uno de los contactos:

listas dinámicas Jetpack Compose

El código fuente es:

package com.tutorialesprogramacionya.compose10

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.Button
import androidx.compose.material.Divider
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            AdministrarContactos()
        }
    }
}

data class Contacto(val nombre: String, val mail: String)

val contactos =  mutableStateListOf<Contacto>()

@Composable
fun AdministrarContactos() {
    var nombre by remember { mutableStateOf("") }
    var mail by remember { mutableStateOf("") }
    Column() {
        OutlinedTextField(value = nombre, onValueChange = {nombre = it},label={Text("Nombre de contacto")},modifier= Modifier
            .fillMaxWidth()
            .padding(5.dp))
        OutlinedTextField(value = mail, onValueChange = {mail = it},label={Text("mail")},modifier= Modifier
            .fillMaxWidth()
            .padding(5.dp))
        Button(onClick = {
            val nuevoContacto=Contacto(nombre,mail)
            contactos.add(nuevoContacto)
            nombre=""
            mail=""
        },modifier=Modifier.padding(5.dp)) {
            Text(text = "Agregar",modifier=Modifier.fillMaxWidth())
        }
        LazyColumn() {
            items (contactos) {contacto->
                MostrarContacto(contacto)
            }
        }
    }
}

@Composable
fun MostrarContacto(contacto:Contacto) {
    Text(text = contacto.nombre)
    Text(text = contacto.mail)
    Divider(modifier= Modifier
        .fillMaxWidth()
        .width(4.dp),color= Color.Black)
}

Fuera de la clase MainActivity y cualquier otra función componible, definimos una variable global que almacenará una lista mutable con estado de la clase 'Contacto':

data class Contacto(val nombre: String, val mail: String)

val contactos =  mutableStateListOf<Contacto>()

Cuando se modifique la lista, por ejemplo se agregue un elemento, Compose se encargará de actualizar en la interfaz visual todos los lugares donde se haga referencia a la misma.

Hemos creado dos funciones componibles, la primera que llamamos desde el MainActivity se llama 'AdministrarContactos'. En esta función definimos dos variables para guardar el estado de los controles OutlineTextField:

    var nombre by remember { mutableStateOf("") }
    var mail by remember { mutableStateOf("") }
    Column() {
        OutlinedTextField(value = nombre, onValueChange = {nombre = it},label={Text("Nombre de contacto")},modifier= Modifier
            .fillMaxWidth()
            .padding(5.dp))
        OutlinedTextField(value = mail, onValueChange = {mail = it},label={Text("mail")},modifier= Modifier
            .fillMaxWidth()
            .padding(5.dp))

También llamamos a la función componible 'Button' y definimos una función lambda para el click del mismo, donde procedemos a llamar al método add para añadir un elemento a la lista mutable (recordemos que esto dispara la recomposición de la pantalla y se muestra el nuevo contacto ingresado):

        Button(onClick = {
            val nuevoContacto=Contacto(nombre,mail)
            contactos.add(nuevoContacto)
            nombre=""
            mail=""

Finalmente llamamos a la función LazyColumn que mostrará cada elemento de la lista 'contactos':

        LazyColumn() {
            items (contactos) {contacto->
                MostrarContacto(contacto)
            }
        }

La segunda función componible que implementamos se llama 'MostrarContacto', la misma tiene por objetivo mostrar el nombre y mail del contacto que llega como parámetro y una línea divisoria:

@Composable
fun MostrarContacto(contacto:Contacto) {
    Text(text = contacto.nombre)
    Text(text = contacto.mail)
    Divider(modifier= Modifier
        .fillMaxWidth()
        .width(4.dp),color= Color.Black)
}

Este proyecto lo puede descargar en un zip desde este enlace: Compose10.zip