Los siguientes modificadores sirven para manipular los datos de un List:
Los modificadores onMove(perform:) y onDelete(perform:) producen un valor de tipo IndexSet que contiene los índices de los valores a cambiar de un arreglo con los métodos:
Cambios visuales automáticos
Al aplicar el modificador - onDelete(perform:) sobre List, el sistema automáticamente habilita la funcionalidad que permite arrastrar las filas hacia la izquierda para hacer visible el botón de "Borrar". Si la lista se crea con un ForEach, entonces se lo debe envolver con List.
struct ContentView: View {
@State var contacts: [Contact] = [
.init(name: "Luis"),
.init(name: "David"),
.init(name: "Goyes"),
.init(name: "Garcés"),
]
var body: some View {
List {
ForEach(contacts) { contact in
Text(contact.name)
}
.onDelete { indexSet in
contacts.remove(atOffsets: indexSet)
}
}
}
}
Modo de edición
Para seleccionar, eliminar y mover filas, la lista debe estar en modo de edición. El modo de edición es un valor del ambiente llamado editMode que se manipula con un Binding.
La forma más fácil de activar el modo de edición es con la vista EditButton que conmuta el valor de editMode.
struct ContentView: View {
@State var contacts: [Contact] = [
.init(name: "Luis"),
.init(name: "David"),
.init(name: "Goyes"),
.init(name: "Garcés"),
]
var body: some View {
NavigationStack {
List {
ForEach(contacts) { contact in
Text(contact.name)
}
.onDelete { indexSet in
contacts.remove(atOffsets: indexSet)
}
.onMove { indexSet, to in
contacts.move(fromOffsets: indexSet, toOffset: to)
}
}
.toolbar {
EditButton()
}
}
}
}
Selección de filas
Para seleccionar una o más filas, debemos inicialiar el List con un Binding en el argumento selection para almacenar el identificador de una o más filas.
Para seleccionar una sola fila, el modo de edición está habilitado por defecto.
struct ContentView: View {
@State var contacts: [Contact] = [
.init(name: "Luis"),
.init(name: "David"),
.init(name: "Goyes"),
.init(name: "Garcés"),
]
@State var selectedContact: Contact.ID?
var body: some View {
NavigationStack {
List(selection: $selectedContact) {
ForEach(contacts) { contact in
Text(contact.name)
}
}
.toolbar {
Button {
if let index = contacts.firstIndex(where: { $0.id == selectedContact }) {
contacts.remove(at: index)
selectedContact = nil
}
} label: {
Label {
Text("Eliminar")
} icon: {
Image(systemName: "trash")
}
}.disabled(selectedContact == nil ? true : false)
}
}
}
}
Para seleccionar múltiples filas, es necesario activar manualmente el modo de edición. Cuando se activa el modo de edición, aparece un "checkbox" al lado izquierdo de la fila para seleccionarla. En el siguiente ejemplo se usa EditButton:
struct ContentView: View {
@State var contacts: [Contact] = [
.init(name: "Luis"),
.init(name: "David"),
.init(name: "Goyes"),
.init(name: "Garcés"),
]
@State var selectedContacts: Set<Contact.ID> = []
var body: some View {
NavigationStack {
List(selection: $selectedContacts) {
ForEach(contacts) { contact in
Text(contact.name)
}
}
.toolbar {
EditButton()
Button {
let indexes = selectedContacts.compactMap { id in
contacts.firstIndex { $0.id == id }
}.reduce(into: IndexSet()) { partialResult, index in
partialResult.insert(index)
}
contacts.remove(atOffsets: indexes)
selectedContacts = []
} label: {
Label {
Text("Eliminar")
} icon: {
Image(systemName: "trash")
}
}.disabled(selectedContacts.count == 0)
}
}
}
}
Manipulando editMode en el ambiente
Para deshabilitar el modo de edición del List de forma programática, se debe inyectar un valor de EditMode por medio del modificador environment(_:_:), con la llave editMode.
Ya no se va a usar EditButton, sino que se va a crear un botón que cambie el estado de edición de la lista por medio de un binding de tipo EditMode. Aunque se podría usar un booleano, e inyectar el EditMode por medio de un Binding de tipo .constant, de esta manera se perdería el caracter reactivo de la inyección del binding al ambiente.
struct ContentView: View {
@State var contacts: [Contact] = [
.init(name: "Luis"),
.init(name: "David"),
.init(name: "Goyes"),
.init(name: "Garcés"),
]
@State var selectedContacts: Set<Contact.ID> = []
@State var editing: EditMode = .inactive
var body: some View {
NavigationStack {
List(selection: $selectedContacts) {
ForEach(contacts) { contact in
Text(contact.name)
}
}
.environment(\.editMode, $editing)
.deleteDisabled(false)
.toolbar {
Button {
editing = (editing == .inactive) ? .active : .inactive
} label: {
Text(editing == .active ? "Listo" : "Editar")
}
Button {
let indexes = selectedContacts.compactMap { id in
contacts.firstIndex { $0.id == id }
}.reduce(into: IndexSet()) { partialResult, index in
partialResult.insert(index)
}
contacts.remove(atOffsets: indexes)
selectedContacts = []
editing = .inactive
} label: {
Label {
Text("Eliminar")
} icon: {
Image(systemName: "trash")
}
}.disabled(selectedContacts.count == 0)
}
}
}
}





Top comments (0)