1

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

  • 1
    Can you update your code listing so that it can actually be compiled and run? You have `@Binding var one: One`, and it probably matters where that is coming from, for starters. Your listing should be the most minimal example that demonstrates your problem. – arsenius Dec 18 '19 at 01:22

1 Answers1

0

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())
    }
}

Hrabovskyi Oleksandr
  • 3,070
  • 2
  • 17
  • 36
  • Thanks very much. It really helped with the problem. – Murray Gordon Dec 18 '19 at 20:13
  • Just following up with this, I have a "plus button" that lets me add items to the list. Using the suggested method I am now unable to add these items to the list. Any suggestions or do you need to see the button code? – Murray Gordon Dec 18 '19 at 20:15
  • @MurrayGordon, sorry for late answer, I'm unable for few days to work. But I'm surprised, why it is so? It must be easy, something like ```Button(action: { self.itemList.items.append(One(item: "third", completed: false)) } ) ...```. Or better to make ```func addItem(_ newItem) { items.append...}``` in ```OneList``` class and it should affect the UI. Text me, does this code work or not, but I'll answer only in few days =( – Hrabovskyi Oleksandr Dec 20 '19 at 05:48
  • The button seems to be working well but I get this from the terminal- AddGestureModifier<_EndedGesture>>> count (2) != its initial count (1). `ForEach(_:content:)` should only be used for *constant* data. Instead conform data to `Identifiable` or use `ForEach(_:id:content:)` and provide an explicit `id`! – Murray Gordon Dec 20 '19 at 07:24
  • Might be something to do with the ForEach(itemList.items.indicies)? – Murray Gordon Dec 20 '19 at 07:25