如何将某些内容附加到列表中?

How to append something to a list?

我现在是 Swift 的新手,我无法添加到待办事项列表。我没有收到错误,所以我不知道出了什么问题。我希望代码不会太多,但我什至不知道问题出在哪里。

有一个 sheet 模式可以正常打开和关闭。唯一的问题是,当我按下保存按钮时,我输入的信息没有添加到列表中。

我添加了 ViewModel、NewTaskView(sheet)、TaskView(自定义列表),以及列表应该位于的 DetailView 的一些代码。


import Foundation
import SwiftUI

class TaskViewModel : Identifiable , ObservableObject {
    
    @Published var tasks : [Task] = [
        Task(taskName: "Lab", taskDate: Date(), taskCompleted: false),
        Task(taskName: "Assignment 4.02", taskDate: Date(), taskCompleted: false)
        
    ]
    
    @Published var sortType : SortType = .alphabetical
    @Published var isPresented = false
    @Published var searched = ""
    
    func addTask(task : Task){
        tasks.append(task)
    }
    
    func removeTask(indexAt : IndexSet){
        tasks.remove(atOffsets: indexAt)
    }
    
    func sort(){
        
        switch sortType {
        case .alphabetical :
            tasks.sort(by: { [=10=].taskName < .taskName })
        case .date :
            tasks.sort(by: { [=10=].taskDate > .taskDate })
        }
    }

}

struct Task : Identifiable , Equatable {
    
    var id : String = UUID().uuidString
    let taskName : String
    let taskDate : Date
    var taskCompleted: Bool
    
}

enum SortType : String , Identifiable , CaseIterable {
    
    var id : String { rawValue }
    
    case alphabetical
    case date
}
    

struct NewTaskView: View {
    
    
    @Environment(\.presentationMode) var presentationMode
    
    @ObservedObject var taskVM : TaskViewModel
    
    @State var taskName = ""
    @State var taskCompleted = Bool()
    @State var taskDate = Date()
    
    
    var body: some View {
        NavigationView {
            VStack(spacing: 14) {
                Spacer()
                
                TextField("Assignment Name",text: $taskName)
                    .padding()
                    .background(Color("tan"))
                    .cornerRadius(5)
                    .font(Font.custom(FontNameManager.Montserrat.semibold, size: 15))
                    .padding(.bottom, 20)
                HStack{
                Text("Due Date")
                        .font(Font.custom(FontNameManager.Montserrat.semibold, size: 15))
                    Image(systemName: "bell.badge")
                    .foregroundColor(.gray)
                    .frame(width: 30, height: 30, alignment: .leading)
                VStack{
                    DatePicker("Select Date", selection: $taskDate, displayedComponents: .date)
                        .labelsHidden()
                }
                }
                HStack{
                    Text("Mark as Completed")
                        .font(Font.custom(FontNameManager.Montserrat.semibold, size: 15))
                    Button(action : {
                        
                        taskCompleted.toggle()
                        
                        
                        
                    }){
                        if taskCompleted == true {
                        Image(systemName: "checkmark.circle.fill")
                                .foregroundColor(Color("orange"))
                                .font(.title2)
                                
                        }
                        else {
                            Image(systemName: "circle")
                                .foregroundColor(Color("lightorange"))
                                .font(.title2)
                                
                                
                        }
                    }
                }
                Spacer()
                
                
                Button(action:{taskVM.addTask(task: .init(taskName: taskName, taskDate: taskDate, taskCompleted: taskCompleted))
                                    
                    presentationMode.wrappedValue.dismiss()},
                                   label:{
                                    Text("Save")
                                   })
                
            }.padding()
                .navigationBarItems(trailing: Button(action: {
                    presentationMode.wrappedValue.dismiss()
                }) {
                    HStack{
                        
                        Image(systemName: "xmark")
                            .foregroundColor(Color("orange"))
                            
                    }
                })
        }
    }
}
struct NewTaskView_Previews: PreviewProvider {
    static var previews: some View {
        NewTaskView(taskVM: TaskViewModel())
        
    }
}

struct TaskView: View {
    
    var task : Task
    
    @Environment(\.managedObjectContext) var moc
    
    @State var currentDate: Date = Date()
    @State var taskCompleted = false
    
    func getDateFormatString(date:Date) -> String
    {
        var dateString = ""
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MMM. dd"
        
        dateString = dateFormatter.string(from: date)
        return dateString
    }
    
    var body: some View {
        HStack {
            Button(action : {
                
                self.taskCompleted.toggle()
                
                try? self.moc.save()
                
            }){
                if self.taskCompleted {
                Image(systemName: "checkmark.circle.fill")
                        .foregroundColor(Color("orange"))
                        .font(.title2)
                        
                }
                else {
                    Image(systemName: "circle")
                        .foregroundColor(Color("lightorange"))
                        .font(.title2)
                        
                        
                }
            }.padding()
            
            VStack (alignment: .leading, spacing: 2){
                Text("\(task.taskName)")
                .font(Font.custom(FontNameManager.Montserrat.bold, size: 18))
                .foregroundColor(Color("dark"))
                .padding([.leading, .trailing], 1)
                
                if self.taskCompleted {
                    Text("Completed")
                        .font(Font.custom(FontNameManager.Montserrat.bold, size: 12))
                        .foregroundColor(Color("burntorange"))
                        .frame(width: 95, height: 20)
                        .background(Color("lightorange"))
                        .cornerRadius(4)
                }
                
                else if currentDate > task.taskDate {
                    Text("Late")
                        .font(Font.custom(FontNameManager.Montserrat.semibold, size: 12))
                        .foregroundColor(.white)
                        .frame(width: 95, height: 18)
                        .background(Color("lightbrown"))
                        .cornerRadius(4)
                        
                }
                
                else {
                    let diffs = Calendar.current.dateComponents([.day], from: currentDate, to: task.taskDate )
                    
                    Text("\(diffs.day!) days left")
                        .font(Font.custom(FontNameManager.Montserrat.semibold, size: 12))
                        .foregroundColor(Color("burntorange"))
                        .frame(width: 95, height: 20)
                        .background(Color("lightorange"))
                        .cornerRadius(4)
                }
            }
            
            Spacer()
            
            Text(getDateFormatString(date: task.taskDate ))
                .font(Font.custom(FontNameManager.Montserrat.medium, size: 12))
                .padding()
            }
        .padding(10)
        .cornerRadius(10)
        .background(
            RoundedRectangle(cornerRadius: 10 , style: .continuous)
                .foregroundColor(.white))
    }
}

struct TaskView_Previews: PreviewProvider {
    static var previews: some View {
        TaskView(task: Task(id: "", taskName: "Task Name", taskDate: Date(), taskCompleted: false))
    }
}

struct DetailsView: View {
    @Environment(\.managedObjectContext) var moc
    
    @ObservedObject var developers : Developer
    @ObservedObject var taskVM : TaskViewModel
    
    @Environment(\.presentationMode) var presen
    @Environment(\.editMode) var editButton
    
    @State var taskCompleted = false
    @State var show = false
    @State var showSearch = false
    @State var txt = ""
    @State var currentDate: Date = Date()
    @State var image : Data = .init(count: 0)
    @State var indices : [Int] = []
    
    func getDateFormatString(date:Date) -> String
    {
        var dateString = ""
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MMM. dd"
        
        dateString = dateFormatter.string(from: date)
        return dateString
    }
    
    var body: some View {
        NavigationView {
            ZStack {
            ZStack{
                VStack{
                    Color("lightorange")
                        .clipShape(CustomCorners(corners: [.bottomLeft, .bottomRight], size: 70))
                        .ignoresSafeArea(.all, edges: .top)
                        .frame(width: 420, height: 175)
                    Spacer()
                }
                
                VStack{
                    HStack {
                        
                        if !self.showSearch{
                        Button(action: {
                            
                            withAnimation(.spring()){
                                self.presen.wrappedValue.dismiss()
                            }
                        }) {
                            Image(systemName: "chevron.left")
                                .font(.title2)
                                .foregroundColor(Color("dark"))
                                .padding(10)
                        }
                        }
                        
                        Spacer(minLength: 0)
                       
                        HStack {

                            if self.showSearch{
                                
                                Image(systemName: "magnifyingglass")
                                    .font(.title2)
                                    .foregroundColor(Color("dark"))
                                    .padding(.horizontal, 8)
                                    
                                
                                TextField("Search", text: $taskVM.searched , onEditingChanged: { (isBegin) in
                                    if isBegin {
                                        showSearch = true
                                    } else {
                                        showSearch = false
                                    }
                                })
                                
                                Button(action: {
                                    withAnimation{
                                    self.showSearch.toggle()
                                    }
                                }) {
                                    
                                    Image(systemName: "xmark").foregroundColor(.black).padding(.horizontal, 8)
                                }
                            }
                            
                            else {
                        Button(action: {
                            withAnimation {
                                
                            self.showSearch.toggle()
                            
                        }
                        }) {
                            Image(systemName: "magnifyingglass")
                                .font(.title2)
                                .foregroundColor(Color("dark"))
                                .padding(10)
                        }
                        }
                        }.padding(self.showSearch ? 10 : 0)
                            .background(Color("lightorange"))
                            .cornerRadius(20)
                        
                    
                    }
                    ZStack{
                      RoundedRectangle(cornerRadius: 25)
                            .foregroundColor(Color("tan"))
                            .frame(width: 335, height: 130)
                        HStack {
                            VStack (alignment: .leading){
                               // Image(uiImage: UIImage(data: developers.imageD ?? self.image)!)
                               //     .resizable()
                               //   .frame(width: 70, height: 70)
                               //    .clipShape(RoundedRectangle(cornerRadius: 20))
                                
                                Text("\(developers.username ?? "")")
                                    .font(Font.custom(FontNameManager.Montserrat.bold, size: 24))
                                    .foregroundColor(Color("dark"))

                                Text("\(developers.descriptions ?? "")")
                                    .font(Font.custom(FontNameManager.Montserrat.semibold, size: 18))
                                    .foregroundColor(.gray)
                                
                            }
                            .padding([.leading, .trailing], 70)
                            .padding(.bottom, 80)
                            
                            Spacer()
                        }
                    }
                    
                    HStack{
                        Text("Assignments")
                            .font(Font.custom(FontNameManager.Montserrat.bold, size: 20))
                        
                        Spacer(minLength: 0)
                        
                        EditButton()
                   
                    }
                    .padding([.leading, .trailing], 20)
                    Spacer()
                    
                List {
                    ForEach (taskVM.tasks.filter {
                        self.taskVM.searched.isEmpty ? true : [=13=].taskName.localizedCapitalized.contains(self.taskVM.searched)} ){ task in
                            TaskView(task: task)
                                .listRowSeparator(.hidden)
            }
                    .onDelete(perform: {
                        taskVM.removeTask(indexAt: [=13=])
                    })
                }
                .listStyle(InsetListStyle())
                    
                }
            }
                VStack {
                    Spacer()
                    HStack {
                        Spacer()
                        ExpandableFAB(taskVM: TaskViewModel(), show: $show)
                    }
                }
                
            }.navigationBarHidden(true)
            .navigationBarBackButtonHidden(true)
        }
    }
}


struct DetailsView_Previews: PreviewProvider {
    static let persistenceController = PersistenceController.shared
    
    static var developers: Developer = {
                let context = persistenceController.container.viewContext
                let developers = Developer(context: context)
                developers.username = "Math"
                developers.descriptions = "Calculus"
                return developers
            }()
    
    static var previews: some View {
        
        DetailsView(developers: developers, taskVM: TaskViewModel()).environment(\.managedObjectContext, persistenceController.container.viewContext)
    }
}

struct ExpandableFAB: View {
    
    @Environment(\.managedObjectContext) var moc
    @ObservedObject var taskVM : TaskViewModel
    
    @Binding var show: Bool
    
    var body: some View{
        
        VStack(spacing: 20){
            
            if self.show{
                Button(action: {
                    taskVM.isPresented.toggle()
                }) {
                    
                    Image(systemName: "list.bullet.rectangle.portrait").resizable().frame(width: 25, height: 25).padding()
                    
                }
                .foregroundColor(.white)
                    .background(Color("orange"))
                    .clipShape(Circle())
                    
                
                Button(action: {
                    self.show.toggle()
                }) {
                    
                    Image(systemName: "doc.badge.plus").resizable().frame(width: 25, height: 25).padding()
                    
                }.foregroundColor(.white)
                    .background(Color("orange"))
                    .clipShape(Circle())
                    
            }
            
            Button(action: {
                self.show.toggle()
                
            }) {
                
                Image(systemName: "plus").resizable().frame(width: 25, height: 25).padding()
                
            }.foregroundColor(.white)
                .background(Color("orange"))
                .clipShape(RoundedRectangle(cornerRadius: 20))
                .padding()
                .rotationEffect(.init(degrees: self.show ? 180 : 0))
            
        }.fullScreenCover(isPresented: $taskVM.isPresented, content: {
            NewTaskView(taskVM: taskVM)
        })
        
    }
}

@burnsi I don't think I have that anywhere. Where should there be one?

当然你有一个,你需要一个:

ExpandableFAB(taskVM: TaskViewModel(), show: $show)

这一行导致了问题。

您以某种方式在 DetailsView 中注入了一个 TaskViewModel(您没有显示位置),但没有使用它。尝试:

ExpandableFAB(taskVM: taskVM, show: $show)

您创建 ViewModel ('TaskViewModel()') 的地方应该有一个 @StateObject 包装器。

解释:

当您向 ViewModel 添加内容时,会重建取决于 ViewModel 的视图。所以你的 TaskViewModel 最终被重新创建,你的数组中仍然有你的 2 个初始值。