- Swifty Snippets
- Posts
- Delete Without Removing Row from List
Delete Without Removing Row from List
An alternative solution to SwiftUI's onDelete
You have a list of items and you want to mark one of them as deleted. You reach for the onDelete
modifier.
struct Record: Identifiable, Equatable {
let id = UUID()
let name: String
var isDeleted: Bool
}
@State private var records: [Record] = [
.init(name: "Jane", isDeleted: false),
.init(name: "Tim", isDeleted: false),
.init(name: "Sam", isDeleted: false),
]
var body: some View {
List {
ForEach(records) { record in
LabeledContent(
record.name,
value: record.isDeleted ? "❌" : "✅"
)
}
.onDelete { indexSet in
for index in indexSet {
records[index].isDeleted = true
}
}
}
}
❌ This causes your row to be removed from the list temporarily, not a nice experience.
Let’s try with swipeActions
var body: some View {
List {
ForEach(records) { record in
LabeledContent(
record.name,
value: record.isDeleted ? "❌" : "✅"
)
.swipeActions(
edge: .trailing,
allowsFullSwipe: true,
content: {
Button("Delete", role: .destructive) {
let index = records.firstIndex(of: record)!
records[index].isDeleted = true
}
}
)
}
}
}
❌ Unfortunately this causes the same problem
What if we remove the button’s role and tint it red?
Button("Delete") {
let index = records.firstIndex(of: record)!
records[index].isDeleted = true
}
.tint(.red)
✅ Works perfectly
One tiny improvement is to not allow swipe to delete for an already deleted record. This requires wrapping our delete button in a conditional check.
if record.isDeleted == false {
Button("Delete") {
let index = records.firstIndex(of: record)!
records[index].isDeleted = true
}
.tint(.red)
}
Perfect