我正在尝试使用
swipeActions
在我的 SwiftUI 应用程序中实现删除功能。当用户在列表项上滑动时,他们应该会看到删除按钮。点击此按钮应在删除项目之前显示确认警报。
但是,我面临一个问题,即一旦出现警报,滑动操作就会自动关闭。这会导致列表项滑回其原始位置,从而不清楚哪个项目将被删除。
我希望在显示警报时滑动操作保持打开状态,以便用户可以清楚地看到他们要确认删除的项目。
这是演示问题的最小代码:
import SwiftUI
struct ContentView: View {
@State private var numbers = Array(1...10)
@State private var showingDeleteAlert = false
@State private var itemToDelete: Int?
var body: some View {
List {
ForEach(numbers, id: \.self) { number in
Text("\(number)")
.swipeActions {
Button(role: .none) {
itemToDelete = number
showingDeleteAlert = true
} label: {
Label("Delete", systemImage: "trash")
}
.tint(.red)
}
}
}
.alert("Confirm", isPresented: $showingDeleteAlert) {
Button("Cancel", role: .cancel) {}
Button("Delete", role: .destructive) {
deleteItem()
}
} message: {
Text("Are you sure you want to delete this item?")
}
}
private func deleteItem() {
if let index = numbers.firstIndex(of: itemToDelete ?? 0) {
numbers.remove(at: index)
}
itemToDelete = nil
}
}
问题:
showingDeleteAlert
会设置为 true
,并且会出现警报。问题:
任何指导或解决方案将不胜感激!
与可以使用
.menuActionDismissBehavior
在选择后保持菜单打开的菜单和选择器不同,我不知道有类似的修改器可以与 .swipeActions
配合使用。
但是,请注意,当滑动按钮显示时,内容将移出视图并且不再可见。因此,保持按钮可见“以便用户可以清楚地看到他们要确认删除的项目”的目标变得毫无意义,因为该项目根本不可见(取决于内容的类型和长度) 。这在你的 GIF 和代码示例中很明显。
因此,您可能需要采取另一种方法,通过在警报/确认消息中包含项目详细信息,让用户清楚地确认他们要删除的项目。
.alert
和 presenting
参数 来完成此操作。由于您已经设置了 itemToDelete
,所以这非常简单:
.alert("Confirm", isPresented: $showingDeleteAlert, presenting: itemToDelete) { item in
Button("Cancel", role: .cancel) {}
Button("Delete", role: .destructive) {
deleteItem()
}
} message: { item in
Text("Are you sure you want to delete item \(item)?")
}
但是,为了避免项目设置和警报显示之间潜在的竞争问题,您可能希望将警报显示为设置要删除的项目的结果,而不是在设置
后立即切换
showingDeleteAlert
itemToDelete
。
完整代码如下:
import SwiftUI
struct SwipeActionDeleteConfirm: View {
@State private var numbers = Array(1...10)
@State private var showingDeleteAlert = false
@State private var itemToDelete: Int?
var body: some View {
List {
ForEach(numbers, id: \.self) { number in
Text("\(number)")
.swipeActions {
Button {
itemToDelete = number
// showingDeleteAlert = true // <- remove this line
} label: {
Label("Delete", systemImage: "trash")
}
.tint(.red)
}
}
}
.onChange(of: itemToDelete){
if itemToDelete != nil {
showingDeleteAlert = true // <- show alert when item changes and is not nil
}
}
//Use .alert with presenting parameter that provides an action closure parameter (item)
.alert("Confirm", isPresented: $showingDeleteAlert, presenting: itemToDelete) { item in // <- note the closure parameter
Button("Cancel", role: .cancel) {
itemToDelete = nil // <- reset itemToDelete on cancel
}
Button("Delete", role: .destructive) {
withAnimation {
deleteItem() // <- optional - delete with animation for a smoother update of the list
}
}
} message: { item in // <- note the closure parameter
Text("Are you sure you want to delete item \(item)?") // <- include the item details/name
}
}
private func deleteItem() {
if let index = numbers.firstIndex(of: itemToDelete ?? 0) {
numbers.remove(at: index)
}
itemToDelete = nil
}
}
#Preview {
SwipeActionDeleteConfirm()
}