Search code examples
swiftstructbooleanswiftuicheckmark

How do I change the bool value of an item that comes from a struct and hence update a checklist?


Background
I am trying to build a list with a checkmark/tick box next to it. A struct is used to create the "data" for each item. This is then passed on to a class which holds an array of the items created by the struct. From here I used the observable object protocol and passed the class into a list.

Objective
I would like to be able to individually mark each item as completed when it is done.

Current Analysis
I know the image switches when I manually change the 'completed' value from false to true. I also tested the onTapAction just to be sure it is working. I think the problem lies in "self.one.completed.toggle()" or the binding or something I am unaware of.

struct One: Identifiable, Codable {
     let id = UUID()
     var item: String
    var completed:Bool = false
}

class OneList: ObservableObject{
    @Published var items1 = [One]()





struct ContentView: View {

    @ObservedObject var itemss1 = OneList()
    @ObservedObject var itemss2 = TwoList()
    @ObservedObject var itemss3 = ThreeList()
    @ObservedObject var itemss4 = FourList()

    @State private var  showingAdditem: Bool = false

    @Binding var one:One

    var body: some View {

        NavigationView{
            ZStack{
                List{
                    Section(header: Text("Vital")){
                        ForEach(itemss1.items1){ item in
                                    HStack{

                                        Image(systemName: self.one.completed ? "checkmark.circle":"circle")
                                            .onTapGesture {
                                                self.one.completed.toggle()

                                        }

                                        Text(item.item)}

P.S. I am relatively new to Swift and Stack overflow so any other suggestions would be appreciated


Solution

  • In my other answer I achieved something like this with ObservableObject protocol for needed object and then playing with EnvironmentObject. Actually I didn't try to do this with other wrappers. Here is the code, where you can see switching images:

    import SwiftUI
    
    class One: Identifiable, ObservableObject { // ObservableObject requires class
    
        let id: UUID
        var item: String = "[undefined]"
        @Published var completed: Bool = false // this will affect the UI
    
        init(item: String, completed: Bool) {
            id = UUID()
            self.item = item
            self.completed = completed
        }
    
    }
    
    class OneList: ObservableObject{
        @Published var items = [One(item: "first", completed: false),
                                One(item: "second", completed: false),
                                One(item: "third", completed: false)]
    }
    
    struct CheckboxList: View {
    
        @EnvironmentObject var itemList: OneList
    
        var body: some View {
            List {
                Section(header: Text("Vital")) {
                    ForEach(itemList.items.indices) { index in
                        VitalRow()
                            .environmentObject(self.itemList.items[index])
                            .onTapGesture {
                                self.itemList.items[index].completed.toggle()
                            }
                    }
                }
            }
        }
    }
    
    struct VitalRow: View {
        @EnvironmentObject var item: One
        var body: some View {
            HStack{
                Image(systemName: item.completed ? "checkmark.circle" : "circle")
                Text("\(item.item)")
            }
        }
    }
    
    struct CheckboxList_Previews: PreviewProvider {
        static var previews: some View {
            CheckboxList().environmentObject(OneList())
        }
    }