List is one of the most used and convenient view in SwiftUI. Lists combined with ForEach adds a few more cool features to the List views.
Today we will explore multi-row delete functionality for List.
We will start with a list of DevTechie courses in a State array property.
struct DevTechieDeleteFromListExample: View {
@State private var courses = ["Mastering WidgetKit iOS 16", "Practical iOS 16", "New in SwiftUI: Charts", "Complete Machine Learning"]
Next we will add variable for EditMode which is a mode that indicates whether the user can edit a view’s content.
struct DevTechieDeleteFromListExample: View {
@State private var courses = ["Mastering WidgetKit iOS 16", "Practical iOS 16", "New in SwiftUI: Charts", "Complete Machine Learning"]
@State private var editingMode = EditMode.inactive
We will add one more State property, this one will hold selections from the List view.
struct DevTechieDeleteFromListExample: View {
@State private var courses = ["Mastering WidgetKit iOS 16", "Practical iOS 16", "New in SwiftUI: Charts", "Complete Machine Learning"]
@State private var editingMode = EditMode.inactive
@State private var selectedItems = Set<String>()
We will create a private computed properties to build delete and edit buttons.
Edit button
: depending upon editing mode for the view, we will show edit or done button on the trailing side of navigation bar.
private var editButton: some View {
Group {
if editingMode == .inactive {
Button(action: {
self.editingMode = .active
self.selectedItems = Set<String>()
}) {
Text("Edit")
}
}
else {
Button(action: {
self.editingMode = .inactive
self.selectedItems = Set<String>()
}) {
Text("Done")
}
}
}
}
Delete button
: We only wanna show delete button when view is in editing mode.
private var deleteButton: some View {
Group {
if editingMode == .inactive {
EmptyView()
} else {
Button(action: deleteCourses) {
Image(systemName: "trash")
}
}
}
}
We will also create a private function to delete selected items from the list of items.
private func deleteCourses() {
for item in selectedItems {
if let index = courses.lastIndex(where: { $0 == item }) {
courses.remove(at: index)
}
}
selectedItems = Set<String>()
}
In the body property, we will add a List inside a NavigationStack and toolbar to add our navigation bar buttons.
var body: some View {
NavigationStack {
List(selection: $selectedItems) {
ForEach(courses, id: \.self) { course in
Text(course)
}
}
.navigationTitle("DevTechie Courses")
.environment(\.editMode, $editingMode)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
deleteButton
}
ToolbarItem(placement: .navigationBarTrailing) {
editButton
}
}
}
}
Complete view should look like this:
struct DevTechieDeleteFromListExample: View {
@State private var courses = ["Mastering WidgetKit iOS 16", "Practical iOS 16", "New in SwiftUI: Charts", "Complete Machine Learning"]
@State private var editingMode = EditMode.inactive
@State private var selectedItems = Set<String>()
private var deleteButton: some View {
Group {
if editingMode == .inactive {
EmptyView()
} else {
Button(action: deleteCourses) {
Image(systemName: "trash")
}
}
}
}
private var editButton: some View {
Group {
if editingMode == .inactive {
Button(action: {
self.editingMode = .active
self.selectedItems = Set<String>()
}) {
Text("Edit")
}
}
else {
Button(action: {
self.editingMode = .inactive
self.selectedItems = Set<String>()
}) {
Text("Done")
}
}
}
}
var body: some View {
NavigationStack {
List(selection: $selectedItems) {
ForEach(courses, id: \.self) { course in
Text(course)
}
}
.navigationTitle("DevTechie Courses")
.environment(\.editMode, $editingMode)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
deleteButton
}
ToolbarItem(placement: .navigationBarTrailing) {
editButton
}
}
}
}
private func deleteCourses() {
for item in selectedItems {
if let index = courses.lastIndex(where: { $0 == item }) {
courses.remove(at: index)
}
}
selectedItems = Set<String>()
}
}
Build and run