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
- Dive into GIT • 8 minutes reading time.
- Build a personal brand as developer • 3 minutes reading time.
- A Guide to UI Testing in Swift • 15 minutes reading time.
Share
Share Bluesky Mastodon Twitter LinkedIn Facebook