Building Editable Lists in SwiftUI
In this post, we will explore how to create editable lists in SwiftUI using a couple of different approaches using EditButton(), @Environment(\.editMode) and custom EditMode state.
What is List, EditButton(), EditMode and @Environment(\.editMode)?
List is a SwiftUI view that presents a scrollable list of rows. It is commonly used to display collections of data in a structured way.
The EditButton() is a built-in SwiftUI button that toggles the edit mode of a view. When tapped, it switches the view between editing and non-editing states, please note this will only update the List's edit mode, it cannot be read from somewhere else in the view.
The EditMode is an enumeration that represents the different states of a view's edit mode. It has two cases we want to use .inactive and .active.
The @Environment(\.editMode) property wrapper allows you to access the current edit mode of the view, enabling you to create editable lists.
Example List with EditButton()
To create an editable list, you can use the List view in combination with EditButton().
struct Pokemon: Identifiable {
let id: UUID
let name: String
init(name: String) {
self.id = UUID()
self.name = name
}
}
struct EditModeView: View {
@State private var pokemon: [Pokemon] = [
.init(name: "Dragonite"),
.init(name: "Lugia"),
.init(name: "Pikachu"),
.init(name: "Mewtwo")
]
@State private var selectedIems: Set<UUID> = []
var body: some View {
NavigationStack {
List(selection: $selectedIems) {
ForEach(pokemon) { pokemon in
Text(pokemon.name)
}
.onDelete { pokemon.remove(atOffsets: $0) }
.onMove { pokemon.move(fromOffsets: $0, toOffset: $1) }
}
.toolbar {
ToolbarItem(placement: .primaryAction) {
EditButton()
}
}
}
}
}
#Preview {
EditModeView()
}
Example List and @Environment(\.editMode)
To create an editable List using @Environment(\.editMode), you can follow this example:
struct EditModeView: View {
@Environment(\.editMode) private var editMode
@State private var name = "Firstname Lastname"
var body: some View {
NavigationStack {
Form {
if editMode?.wrappedValue.isEditing == true {
TextField("Name", text: $name)
} else {
Text(name)
}
}
.animation(nil, value: editMode?.wrappedValue)
.toolbar {
EditButton()
}
}
}
}
#Preview {
EditModeView()
}
Example List with custom EditMode
To create an editable List using a custom EditMode state, you can follow this example:
import SwiftUI
struct Pokemon: Identifiable {
let id: UUID
let name: String
init(name: String) {
self.id = UUID()
self.name = name
}
}
struct EditModeView: View {
// Custom edit mode.
@State var editMode: EditMode = .inactive
@State private var pokemon: [Pokemon] = [
.init(name: "Dragonite"),
.init(name: "Lugia"),
.init(name: "Pikachu"),
.init(name: "Mewtwo")
]
@State private var selectedIems: Set<UUID> = []
var body: some View {
NavigationStack {
List(selection: $selectedIems) {
ForEach(pokemon) { pokemon in
Text(pokemon.name)
}
.onDelete { pokemon.remove(atOffsets: $0) }
.onMove { pokemon.move(fromOffsets: $0, toOffset: $1) }
}
// Tell the List that we are if editting
.environment(\.editMode, $editMode)
.toolbar {
ToolbarItem(placement: .primaryAction) {
// Toggle editmode
Button(editMode.isEditing ? "Done" : "Edit") {
withAnimation {
editMode = editMode.isEditing ? .inactive : .active
}
}
}
ToolbarItem(placement: .bottomBar) {
VStack {
Text("Selected: \(selectedIems.count), edit mode: \(editMode.isEditing)")
HStack {
if selectedIems.isEmpty {
Button("Select All") {
selectedIems.formUnion(pokemon.map(\.id))
editMode = .active
}
} else {
Button("Deselect All") {
selectedIems.removeAll()
editMode = .inactive
}
}
Spacer()
Button("Delete") {
pokemon.removeAll(where: {
selectedIems.contains($0.id)
})
selectedIems = []
editMode = .inactive
}
.disabled(selectedIems.isEmpty)
.disabled(!editMode.isEditing)
.frame(maxWidth: .infinity)
}
}
.frame(maxWidth: .infinity)
}
}
}
}
}
#Preview {
EditModeView()
}
Caveats
@Environment(\.editMode) only passes the EditMode to the List/Form and will not be updated anywhere else, that's why you need to manage the edit mode state manually if you want to support "Select All", "Deselect All", and "Delete" as a button.
Wrap up
In this article, we explored how to create editable lists in SwiftUI using a custom edit mode. We covered the basics of managing selection and deletion of items, as well as how to toggle edit mode. With these techniques, you can create more interactive and user-friendly list interfaces in your SwiftUI applications.
Resources:
-
https://developer.apple.com/documentation/swiftui/editbutton
-
https://developer.apple.com/documentation/swiftui/environmentvalues/editmode
Read more
- Swift Package: PreventScreenshot • 2 minutes reading time.
- Apple version numbers • 1 minutes reading time.
- Swift Package: ImagePicker • 2 minutes reading time.
Share
Share Bluesky Mastodon Twitter LinkedIn Facebook