我如何使用位于列表内部的按钮删除列表中的项目?

huangapple go评论116阅读模式
英文:

How would I delete items from a list with a button inside that list?

问题

SwiftUI
[这是列表和按钮的代码]

ForEach(items, id: \.self) { current in 
    VStack(alignment: .leading) {
        Text("\(current.task)")
            .padding(2)
        Text("\(dateFormatter.string(from: current.date))")
        Button(action: {}, 
               label: {
                    Image(systemName: 
                      "checkmark.rectangle.fill")
                        .resizable()
                        .frame(width: 50, height: 35)
               }) 
    }
}

Items 是包含字符串和日期的数组。以下是其代码:

@State var items: [Tasks] = [Tasks(task: "测试", date: Date())]

这是 Tasks 结构体:

struct Tasks: Hashable {
    let task: String
    let date: Date 
}

这是我的列表视图

我希望用户能够点击每个列表项下面的按钮,以删除该列表项。我目前使用 onDelete 方法,但我更希望在每个列表项下面有一个确认按钮,允许用户删除该列表项。

@State var counter = -1 

我尝试使用一个计数器,使其在 ForEach 循环运行时递增,并在该 ForEach 循环内创建一个等于计数器值的新变量。然而,我无法在按钮内访问该变量以用作索引。

英文:

SwiftUI
[This is the code for the list and my button]

ForEach(items, id: \.self) { current in 
                VStack(alignment: .leading) {
                    Text("\(current.task)")
                        .padding(2)
                    Text("\(dateFormatter.string(from: current.date))")
                    Button(action: {}, 
                           label: {
                                    Image(systemName: 
                                      "checkmark.rectangle.fill")
                            .resizable()
                            .frame(width: 50, height: 35)
                           }) 
}

Items is my array containing a string and a date. Here is the code for it:

@State var items:[Tasks] = [Tasks(task: "Test", date: Date())]

And here is Tasks:

struct Tasks: Hashable {
  let task: String
  let date: Date 
}

This is my list view

I want to have a user be able to click a button under each list item and it will remove that list item. I am currently using the onDelete method but I would prefer to have a confirm button in each list item that would allow the user to remove that list item.

    @State var counter = -1 

I tried using a counter that would increase by 1 each time the ForEach loop ran and create a new variable inside of that ForEach loop equal to it. However I could not access the variable inside of the button to use as an index.

答案1

得分: 1

根据您当前的代码结构,假设每个 task: String 都是唯一的,您可以将以下代码添加到您的 Button 操作中:

Button(action: {
    if let index = items.firstIndex(where: {$0.task == current.task}) {
        items.remove(at: index)
    }
},
label: {
    Image(systemName: "checkmark.rectangle.fill")
        .resizable()
        .frame(width: 50, height: 35)
})

然而,为了使代码更加健壮,建议为您的 Task 添加一个 id 属性,并同时重命名它,因为Swift已经将 Task 定义为其异步/等待框架的一部分。

以下是我用于测试我的答案的完整代码:

struct MyTask: Identifiable, Hashable {
    let id = UUID()
    let task: String
    let date: Date
}

struct ContentView: View {
    @State var items:[MyTask] = [
        MyTask(task: "Test1", date: Date()),
        MyTask(task: "Test2", date: Date().addingTimeInterval(60*60*24*44)),
        MyTask(task: "Test3", date: Date().addingTimeInterval(60*60*24*88))
    ]

    var body: some View {
        ForEach(items) { current in
            VStack(alignment: .leading) {
                Text(current.task).padding(2)
                Text(dateFormatter.string(from: current.date))
                Button(action: {
                    if let index = items.firstIndex(where: {$0.id == current.id}) {
                        items.remove(at: index)
                    }
                },
                label: {
                    Image(systemName: "checkmark.rectangle.fill").resizable()
                        .frame(width: 50, height: 35)
                })
            }
        }
    }

    var dateFormatter: DateFormatter = {
        let frmt = DateFormatter()
        frmt.dateFormat = "yyyy-MMM-dd"
        return frmt
    }()
}

请注意,我已经将 HTML 实体(例如 <")转换为正常的Swift代码。

英文:

Using your current code structure, assuming each task: String is unique, you could just add this to your Button action:

 Button(action: {
     if let index = items.firstIndex(where: {$0.task == current.task}) {
         items.remove(at: index)
     }
 },
        label: {
     Image(systemName: "checkmark.rectangle.fill")
         .resizable()
         .frame(width: 50, height: 35)
 })

However, it would be more robust to add an id property to your Task, and
at the same time rename it, because Swift already defines Task as part of its async/await framework.

Here is the complete code I use to test my answer:

struct MyTask: Identifiable, Hashable { // <--- here
  let id = UUID() // <--- here
  let task: String
  let date: Date
}

struct ContentView: View {
    @State var items:[MyTask] = [
        MyTask(task: "Test1", date: Date()),
        MyTask(task: "Test2", date: Date().addingTimeInterval(60*60*24*44)),
        MyTask(task: "Test3", date: Date().addingTimeInterval(60*60*24*88))
    ]
    
    var body: some View {
        ForEach(items) { current in     // <--- here
            VStack(alignment: .leading) {
                Text(current.task).padding(2)  // <--- here
                Text(dateFormatter.string(from: current.date))  // <--- here
                Button(action: {
                    // --- here
                    if let index = items.firstIndex(where: {$0.id == current.id}) {
                        items.remove(at: index)
                    }
                },
                       label: {
                    Image(systemName: "checkmark.rectangle.fill").resizable()
                        .frame(width: 50, height: 35)
                })
            }
        }
    }
    
    var dateFormatter: DateFormatter = {
        let frmt = DateFormatter()
        frmt.dateFormat = "yyyy-MMM-dd"
        return frmt
    }()
}

huangapple
  • 本文由 发表于 2023年2月19日 06:31:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/75496794.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定