SwiftUI多选删除列表元素
SwiftUI多选删除列表元素

SwiftUI多选删除列表元素

在SwiftUI中可以通过ForEach的onDelete方法删除列表项,但因为onDelete方法不提供多选删除的直接支持,因此可以设置选择状态并在编辑模式下启用批量删除功能。

实现批量删除的思路

1、管理选中状态:引入一个字典来存储每个书籍项的选中状态。

2、批量删除按钮:在 Edit 模式下显示一个“批量删除”按钮,用户可以选择多个项并一次性删除。

3、修改 ForEach 结构:为每行增加一个复选框或按钮,用户可以选择每一行。

4、批量删除逻辑:当“批量删除”按钮被点击时,删除所有选中的项。

示例代码

struct ContentView: View {
    @Environment(\.modelContext) var modelContext
    @Query var books: [Book]
    @State private var isEditing = false // 控制编辑模式
    @State private var selectedBooks = Set<Book>() // 存储选中的书籍项
    func deleteSelectedBooks() {
        for book in selectedBooks {
            modelContext.delete(book)
        }
        selectedBooks.removeAll() // 清空已删除项
    }
    var body: some View {
        NavigationStack {
            List {
                ForEach(books) { book in
                    HStack {
                        if isEditing {
                            Button(action: {
                                if selectedBooks.contains(book) {
                                    selectedBooks.remove(book)
                                } else {
                                    selectedBooks.insert(book)
                                }
                            }) {
                                Image(systemName: selectedBooks.contains(book) ? "checkmark.circle.fill" : "circle")
                                    .foregroundColor(.blue)
                            }
                        }
                        NavigationLink(value: book) {
                            HStack {
                                VStack(alignment: .leading) {
                                    Text(book.title)
                                        .font(.headline)
                                    Text(book.author)
                                        .foregroundStyle(.secondary)
                                }
                            }
                        }
                    }
                }
            }
            .navigationTitle("Bookworm")
            .toolbar {
                ToolbarItem(placement: .topBarLeading) {
                    Button(action: {
                        print("点击了自定义的修改按钮")
                        isEditing.toggle()
                    }, label: {
                        Image(systemName: "square.and.pencil")
                    })
                }
                if isEditing {
                    ToolbarItem(placement: .bottomBar) {
                        Button("Delete Selected") {
                            deleteSelectedBooks()
                        }
                        .disabled(selectedBooks.isEmpty) // 只有当有选中项时才能批量删除
                    }
                }
            }
        }
    }
}

代码解析

1、控制变量
@State private var isEditing = false // 控制编辑模式

@State private var isEditing:一个布尔值,用于控制是否处于编辑模式。在点击 EditButton 时切换 isEditing 状态。

@State private var selectedBooks = Set<Book>() // 存储选中的书籍项

@State private var selectedBooks:一个集合,用来存储用户选择的书籍。在编辑模式下,用户可以点击选择多本书。

2、列表管理
List {
    ForEach(books) { book in
        HStack {
            if isEditing {
                Button(action: {
                    if selectedBooks.contains(book) {
                        selectedBooks.remove(book)
                    } else {
                        selectedBooks.insert(book)
                    }
                }) {
                    Image(systemName: selectedBooks.contains(book) ? "checkmark.circle.fill" : "circle")
                        .foregroundColor(.blue)
                }
            }
            NavigationLink(value: book) {
                HStack {
                    VStack(alignment: .leading) {
                        Text(book.title)
                            .font(.headline)
                        Text(book.author)
                            .foregroundStyle(.secondary)
                    }
                }
            }
        }
    }
}

在ForEach中,添加了一个点击按钮,当isEditing为true时,表示处于编辑状态下并显示对应的按钮,否则不显示。

该按钮的作用为:当点击该按钮时,检查当前元素是否存在selectedBooks数组中,如果存在则移除该元素,同时Image展示为“circle”,如果selectedBooks数组中没有该元素,则添加到数组中并将Image展示为“checkmark.circle.fill”。

3、多选按钮

在 ForEach 的 HStack 中,添加一个按钮,通过选中和取消选中书籍来更新 selectedBooks。

.toolbar {
    ToolbarItem(placement: .topBarLeading) {
        Button(action: {
            print("点击了自定义的修改按钮")
            isEditing.toggle()
        }, label: {
            Image(systemName: "square.and.pencil")
        })
    }
    if isEditing {
        ToolbarItem(placement: .bottomBar) {
            Button("Delete Selected") {
                deleteSelectedBooks()
            }
            .disabled(selectedBooks.isEmpty) // 只有当有选中项时才能批量删除
        }
    }
}

两个按钮分别位于视图的左上角和底部,当点击.topBarLeading位置的按钮时,会切换isEditing的状态,如果isEditing为true,则展示前面提到的按钮以及展示底部的“Delete Selected”按钮。

多选列表后,点击底部的“Delete Selected”按钮后,会调用deleteSelectedBooks方法。

4、删除按钮逻辑

deleteSelectedBooks 遍历 selectedBooks 集合,将其中的书籍项从 modelContext 中删除,并清空集合。

func deleteSelectedBooks() {
    for book in selectedBooks {
        modelContext.delete(book)
    }
    selectedBooks.removeAll() // 清空已删除项
}

这里之所以使用for-in方法,是因为selectedBooks数组不是单独的元素,可能在选择的过程中选择了多个元素,因此需要进行遍历删除。

列表选择中存在selectedBooks数组的逻辑:

if isEditing {
    Button(action: {
        if selectedBooks.contains(book) {
            selectedBooks.remove(book)
        } else {
            selectedBooks.insert(book)
        }
    }) {
        Image(systemName: selectedBooks.contains(book) ? "checkmark.circle.fill" : "circle")
            .foregroundColor(.blue)
    }
}

所以,在列表中通过对selectedBooks的添加或移除,来汇总多选并需要展示的数组元素,然后通过相关的删除方法删除元素。

modelContext.delete(book)

是SwiftData的删除方法,如果是数组元素,则可以使用

books.remove(atOffsets: book) // 从数组中删除项目

相关资料

SwiftUI删除元素的onDelete方法:https://fangjunyu.com/2024/09/27/swift-ui-ondelete%e5%87%bd%e6%95%b0/

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注