9 - Eliminar elementos a listas dinámica de datos

Vimos en el concepto anterior como agregamos un elemento a una lista creada con la función mutableStateListOf y como se refleja automáticamente en la pantalla gracias a Compose, ahora veremos que si eliminamos un elementos sucede lo mismo en la interfaz visual.

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. Agregar un botón que lo pueda eliminar de la lista.

Creamos el proyecto llamado 'Compose11'.

La interfaz visual a implementar es:

eliminar elemento de una lista Jetpack Compose

El código que debemos implementar para poder eliminar elementos de una lista que mantiene el estado es:

package com.tutorialesprogramacionya.compose11

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
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.itemsIndexed
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
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>(
    Contacto("Martinez Luis", "mluis@gmail.com"),
    Contacto("Rodriguez Pablo", "rpablo@hotmail.com"),
    Contacto("Conesa Nestor", "cnestor@hotmail.com"),
    Contacto("Lopez Ana", "lana@yahoo.com")
)

@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() {
            itemsIndexed(contactos) { indice, contacto ->
                MostrarContacto(indice, contacto)
            }
        }
    }
}

@Composable
fun MostrarContacto(indice: Int, contacto: Contacto) {
    Text(text = contacto.nombre)
    Text(text = contacto.mail)
    Image(painter = painterResource(id = android.R.drawable.ic_delete), contentDescription = "",
        modifier = Modifier.clickable {
            contactos.removeAt(indice)
        })
    Divider(
        modifier = Modifier
            .fillMaxWidth()
            .width(4.dp), color = Color.Black
    )
}

La lista comienza con 4 contactos previamente cargados:

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

val contactos = mutableStateListOf<Contacto>(
    Contacto("Martinez Luis", "mluis@gmail.com"),
    Contacto("Rodriguez Pablo", "rpablo@hotmail.com"),
    Contacto("Conesa Nestor", "cnestor@hotmail.com"),
    Contacto("Lopez Ana", "lana@yahoo.com")
)

Para recorrer la lista hemos utilizado la función itemsIndexed, la diferencia con la función vista anteriormente items es que la función lambda recibe también el índice del elemento (el cual nos servirá después para saber cual elemento eliminar):

        LazyColumn() {
            itemsIndexed(contactos) { indice, contacto ->
                MostrarContacto(indice, contacto)
            }
        }

En este caso hemos dispuesto una imagen en lugar de un botón para eliminar el elemento de la lista de contactos:

    Image(painter = painterResource(id = android.R.drawable.ic_delete), contentDescription = "",
        modifier = Modifier.clickable {
            contactos.removeAt(indice)
        })

La imagen la extraemos de las existentes en Android. Para la captura del click en una imagen debemos modificar el parámetro modifier y llamar a la función clickable pasando la función lambda que debe remover el elementos de la lista de contactos (utilizamos el índice que ocupa en la lista al llamar a removeAt)

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