Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to remove a row in a list in SwiftUI?

Tags:

swiftui

I have created a quiet simple list in SwiftUI and want to make it editable, like a tableView in UIKit. I want to remove a row in the list with the all known gesture (swipe from, the right to the left).

I have tried to make with a button above the list, but it doesn't look nice an is not practicable for my app.

struct singleIsland: Identifiable {
    let id: Int
    let name:String
}

var islands = [
singleIsland(id: 0, name: "Wangerooge"),
singleIsland(id: 1, name: "Spiekeroog"),
singleIsland(id: 2, name: "Langeoog")
]

var body: some View {
    VStack {

        List(islands) { island in
            Text(island.name)
        }
    }
}
like image 740
Libiph Avatar asked Jun 12 '19 14:06

Libiph


3 Answers

struct SingleIsland {
    let name: String
}

struct ContentView: View {

    @State var islands = [
        SingleIsland(name: "Wangerooge"),
        SingleIsland(name: "Spiekeroog"),
        SingleIsland(name: "Langeoog")
    ]

    var body: some View {
        List {
            ForEach(islands.identified(by: \.name)) { island in
                Text(island.name)
            }.onDelete(perform: delete)
        }
    }

    private func delete(with indexSet: IndexSet) {
        indexSet.forEach { islands.remove(at: $0) }
    }
}

Wrapping the data in a @State makes sure the view is redrawn if it changes.


Note:

I'm getting compilers errors if the List is built this way:

List(data) { item in
 [...]
}

It will complain that onDelete does not exist for the List.

My workaround is to use a ForEach inside the List, and the onDelete function on it.

like image 140
Matteo Pacini Avatar answered Sep 27 '22 17:09

Matteo Pacini


Yes, this is very straight forward with SwiftUI.

Updating your code like this...

struct SingleIsland: Identifiable {
    let id: Int
    let name:String
}

struct IslandListView: View {
    @State private var islands = [
        SingleIsland(id: 0, name: "Wangerooge"),
        SingleIsland(id: 1, name: "Spiekeroog"),
        SingleIsland(id: 2, name: "Langeoog")
    ]

    var body: some View {
        List {
            ForEach(islands.identified(by: \.name)) { island in
                Text(island.name)   
            }.onDelete(perform: delete)
        }
    }

    func delete(at offsets: IndexSet) {
        islands.remove(at: offsets)
    }
}

This will allow your view to swipe to delete rows.

Using @State sets up your view to depend on the islands array. Any update to that array will trigger the view to reload. So by deleting an item from the array it will animate the change to the list.

like image 39
Fogmeister Avatar answered Sep 27 '22 17:09

Fogmeister


Add this to the list:

.onDelete { $0.forEach { islands.remove(at: $0) } }

After you turning islands into an @State

like image 33
Mojtaba Hosseini Avatar answered Sep 27 '22 17:09

Mojtaba Hosseini