【问题标题】:SwiftUI `swipeActions` and `confirmationDialog` delete the wrong itemSwiftUI `swipeActions` 和 `confirmationDialog` 删除错误的项目
【发布时间】:2021-11-18 10:27:34
【问题描述】:

我正在尝试使用 iOS 15.0 swipeActionsconfirmationDialog 删除 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
                }
            }
    }
}

}

输出是:

Trying to delete: Two
Actually deleting: Four
Trying to delete: Five
Actually deleting: Three

所以我刷了一个项目并显示confirmationDialog。但是在confirmationDialog 内部传递了另一个项目。这是为什么呢?

【问题讨论】:

    标签: ios swift swiftui


    【解决方案1】:

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

    我知道这是多么令人沮丧!

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

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

    【讨论】:

    • 这绝对有效。谢谢你。将itemToDelete 的值保存在另一个变量中,直到用户确认删除不是最优雅的解决方案,但它确实有效。你对多个confirmationDialogs 的解释很有道理。
    • 是否有适用于 iPad 的解决方法?该解决方案有效,但现在 confirmationDialog 始终附加到 List 而不是 List 内的正确项目。
    【解决方案2】:

    Scott 的解决方案运行良好,但是当您想在 iPad 上显示 confirmationDialog 时,附件已关闭(因为它现在使用列表作为附件)。请看下面的截图:

    您可以通过将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)
                }
            }
        }
    }
    

    截图:

    【讨论】:

      猜你喜欢
      • 2021-08-29
      • 1970-01-01
      • 2021-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多