SwiftUI `swipeActions` 和 `confirmationDialog` 删除了错误的项目

Ton*_*ony 6 ios swift swiftui

我正在尝试使用 iOS 15.0swipeActionsconfirmationDialog删除List.

但发生的情况是错误的项目被删除了。

这是我的代码:

struct ConversationsSection: View {

@State private var isShowingDeleteActions = false

let items = ["One", "Two", "Three", "Four", "Five"]

var body: some View {
    List(items, id: \.self) { item in
        Text(item)
            .swipeActions(edge: .trailing) {
                Button(role: .destructive) {
                    isShowingDeleteActions = true
                    print("Trying to delete: " + item)
                } label: {
                    Label("Delete", systemImage: "trash")
                }
            }
            .confirmationDialog("Delete item?", isPresented: $isShowingDeleteActions) {
                Button("Confirm Delete", role: .destructive) {
                    print("Actually deleting: " + item)
                    isShowingDeleteActions = false
                }
            }
    }
}
Run Code Online (Sandbox Code Playgroud)

}

输出是:

Trying to delete: Two
Actually deleting: Four
Trying to delete: Five
Actually deleting: Three
Run Code Online (Sandbox Code Playgroud)

所以我滑动一个项目并confirmationDialog显示出来。但里面confirmationDialog又传递了另一个项目。这是为什么?

Sco*_*man 9

我是这样想的:confirmationDialogForEach 循环中有一个修饰符,因此有多个确认对话框,其显示由单个$isShowingDeleteActions状态变量控制。发生这种情况时,SwiftUI 无法可靠地显示设置状态变量 \xe2\x80\x93 的循环实例中的对话框,因此它最终可能会显示不同的对话框并且其item值不同。

\n

我明白这是多么令人沮丧!

\n

一种解决方法是将确认对话框完全移出循环,因此只有一个修饰符使用$isShowingDeleteActions. 问题在于不再直接引用item,但我们可以通过在第二个状态变量中保留引用来进行补偿:

\n
struct ConversationsSection: View {\n\n@State private var isShowingDeleteActions = false\n@State private var itemToDelete: Item? = nil\n\nvar body: some View {\n    List(items, id: \\.self) { item in\n        Text(item)\n            .swipeActions(edge: .trailing) {\n                Button(role: .destructive) {\n                    itemToDelete = item\n                    isShowingDeleteActions = true\n                } label: {\n                    Label("Delete", systemImage: "trash")\n                }\n            }\n    }\n    .confirmationDialog("Delete item?", isPresented: $isShowingDeleteActions) {\n        Button("Confirm Delete", role: .destructive) {\n            if let item = itemToDelete {\n                print("Actually deleting: " + item)\n                isShowingDeleteActions = false\n                itemToDelete = nil\n            }\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n


Ese*_*era 5

Scott 的解决方案工作正常,但是当您想在 iPad 上显示 时confirmationDialog,附件会关闭(因为它现在使用列表作为附件)。请参阅下面的屏幕截图:

iPad 附件问题截图

您可以通过将Text及其修饰符和属性一起提取@State到新视图中来解决此问题,如下所示:

import SwiftUI

struct ItemView: View {
    
    @State private var isShowingDeleteActions = false
    
    var item: String
    
    var body: some View {
        Text(item)
            .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
            .swipeActions(edge: .trailing) {
                Button(role: .destructive) {
                    isShowingDeleteActions = true
                    print("Trying to delete: " + item)
                } label: {
                    Label("Delete", systemImage: "trash")
                }
            }
            .confirmationDialog("Delete item?", isPresented: $isShowingDeleteActions) {
                Button("Confirm Delete", role: .destructive) {
                    print("Actually deleting: " + item)
                    isShowingDeleteActions = false
                }
            }
    }
}

struct ConversationsSection: View {

    let items = ["One", "Two", "Three", "Four", "Five"]

    var body: some View {
        NavigationView {
            List(items, id: \.self) { item in
                ItemView(item: item)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

截图如下:

iPad 截图,附件正确