Swiftui:我如何在VSTACK中删除foreach行?

发布于 2025-01-19 19:06:48 字数 1391 浏览 4 评论 0原文

这是TaskModel

import Foundation
import SwiftUI


struct TaskModel: Identifiable, Codable {
    var id = UUID().uuidString
    var title : String
    var selectedColor : Color
    var remindedTime : Int
    var taskDate : Date
}

这是我尝试过的ViewModel

    import Foundation
    import SwiftUI
    
    class CalendarViewModel : ObservableObject {
        
        @Published var tasks : [TaskModel] = []
        @Published var currentMonth : Int = 0
        
    
        func addTask(title : String, selectedColor : Color, reminderTime : Int, taskDate : Date) {
            let newTask = TaskModel(title: title, selectedColor: selectedColor, remindedTime: reminderTime * 60, taskDate: taskDate)
            tasks.append(newTask)
        }
        
        func deleteTask(task : TaskModel) {
            if let index = tasks.firstIndex(where: {$0.id == task.id }) {
                tasks.remove(at: index)
            }
        }

这是我尝试删除行的ForEach

VStack {
                    ForEach(vm.tasks.filter({vm.isSameDay(date1: $0.taskDate, date2: currentDate)})) { task in
                        TaskRowView(task: task)
                            .actionSheet(isPresented: $isShowActionSheet) {
                                ActionSheet(title: Text("Settings"), message: Text("Press the button that what you want to do 
              

This is TaskModel

import Foundation
import SwiftUI


struct TaskModel: Identifiable, Codable {
    var id = UUID().uuidString
    var title : String
    var selectedColor : Color
    var remindedTime : Int
    var taskDate : Date
}

This is ViewModel I tried

    import Foundation
    import SwiftUI
    
    class CalendarViewModel : ObservableObject {
        
        @Published var tasks : [TaskModel] = []
        @Published var currentMonth : Int = 0
        
    
        func addTask(title : String, selectedColor : Color, reminderTime : Int, taskDate : Date) {
            let newTask = TaskModel(title: title, selectedColor: selectedColor, remindedTime: reminderTime * 60, taskDate: taskDate)
            tasks.append(newTask)
        }
        
        func deleteTask(task : TaskModel) {
            if let index = tasks.firstIndex(where: {$0.id == task.id }) {
                tasks.remove(at: index)
            }
        }

This is the ForEach I tried to delete row

VStack {
                    ForEach(vm.tasks.filter({vm.isSameDay(date1: $0.taskDate, date2: currentDate)})) { task in
                        TaskRowView(task: task)
                            .actionSheet(isPresented: $isShowActionSheet) {
                                ActionSheet(title: Text("Settings"), message: Text("Press the button that what you want to do ????"), buttons: [
                                    .cancel(), .destructive(Text("Delete"), action: {
                                        vm.deleteTask(task: task)
                                    }), .default(Text("Edit"), action: {
                                        
                                    })
                                ])
                            }
                    }
                    
                    .onLongPressGesture {
                        isShowActionSheet.toggle()
                    }
                 }

And this is the picture of my app View.
enter image description here

The weird thing is when I tried to delete second row of the List, The first row is deleted and second is left.

But, I can't find my miss point.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夜空下最亮的亮点 2025-01-26 19:06:48

实现此目的的最简单方法是使用可选的选择变量和 .actionSheet() 的自定义绑定。请参阅下面的代码。我评论了重要的部分。为了演示目的,我还将您的代码更改为最小可重现示例 (MRE)

struct ContentView: View {
    
    @State var tasks = Array(1...20).map( { TaskModel(title: "Task \($0)") })
    // This is your optional selection variable
    @State var selectedRow: TaskModel?
    
    var body: some View {
        VStack {
            ForEach(tasks) { task in
                Text(task.title)
                    // put the .onLongPressGesture() on the row itself
                    .onLongPressGesture {
                        // set selectedRow to the task
                        selectedRow = task
                    }
                    // This creates a custom binding
                    .actionSheet(isPresented: Binding<Bool>(
                        // the get returns the Bool that is the comparison of selectedRow and task
                        // if they are equal, the .actionSheet() fires
                        get: { selectedRow == task },
                        // when done, .actionSheet() sets the Binding<Bool> to false, but we intercept that
                        // and use it to set the selectedRow back to nil
                        set: { if !$0 {
                            selectedRow = nil
                        }})) {
                        ActionSheet(
                            title: Text("Settings"),
                            // added task.title to prove the correct row is in the ActionSheet
                            message: Text("Press the button for \(task.title)"),
                            buttons: [
                                .cancel(),
                                .destructive(Text("Delete"), action: {}),
                                .default(Text("Edit"), action: {})
                            ]
                        )
                    }
            }
        }
    }
}

The simplest way to implement this is with an optional selection variable and a custom binding for the .actionSheet(). Please see the code below. I commented the important parts. I also changed your code to a Minimal Reproducible Example (MRE) for demonstration purposes.

struct ContentView: View {
    
    @State var tasks = Array(1...20).map( { TaskModel(title: "Task \($0)") })
    // This is your optional selection variable
    @State var selectedRow: TaskModel?
    
    var body: some View {
        VStack {
            ForEach(tasks) { task in
                Text(task.title)
                    // put the .onLongPressGesture() on the row itself
                    .onLongPressGesture {
                        // set selectedRow to the task
                        selectedRow = task
                    }
                    // This creates a custom binding
                    .actionSheet(isPresented: Binding<Bool>(
                        // the get returns the Bool that is the comparison of selectedRow and task
                        // if they are equal, the .actionSheet() fires
                        get: { selectedRow == task },
                        // when done, .actionSheet() sets the Binding<Bool> to false, but we intercept that
                        // and use it to set the selectedRow back to nil
                        set: { if !$0 {
                            selectedRow = nil
                        }})) {
                        ActionSheet(
                            title: Text("Settings"),
                            // added task.title to prove the correct row is in the ActionSheet
                            message: Text("Press the button for \(task.title)"),
                            buttons: [
                                .cancel(),
                                .destructive(Text("Delete"), action: {}),
                                .default(Text("Edit"), action: {})
                            ]
                        )
                    }
            }
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文