yama_HD
yama_HD

Reputation: 568

SwiftUI Clicking on one Row in a List, sets every row on that list to true

I have a List that looks like that:

enter image description here

But when I click on one row, every circle in every row gets activated/deactivated. I am sitting on that problem for a few Hours now and don't know what to do. Can anyone help me?

I think the problem has something to do with the DispatchQueue.main.async Line. But if I don't use DispatchQueue.main.async in the code, the list is empty and cannot be filled. And if I wouldn't do DispatchQueue.main.async, I get the following Error twice:

Modifying state during view update, this will cause undefined behavior.

So if I use DispatchQueue.main.async the list can be filled and is not empty. But as I described earlier, the new Problem is, that when I click a Row, every Circle(from all rows) in the list gets activated/deactivated.

This is my code:

struct zettelDetailView: View {
    
    var info: CreateInfo
    
    @State var isChecked: Bool = false
    
    func toggle(){
        isChecked = !isChecked
    }
    
    @State var listItems = [CreateZettelDetailViewText]()
    @State var executeThisAsyncThing: Bool = true

    
        private func changeInfoListToArray() {
            
            //String ist folgendermaßen aufgebaut:
            //"Text/-t;" t = true; f = false "/-" und ";" sind splitter
    //        var returnArray = [CreateZettelDetailViewText]()
            
    //        let infoStr = info.list
            let infoStr = "Das-t;Ist-f;Ein-f;Test-t;"
            
            let infoArr1 = infoStr.split(separator: ";")
            
            var infoArr2 = [[String]]()
            
            print(infoArr1.count)
            
            if infoArr1.count != 0 {
                for i in 0...(infoArr1.count - 1) {
                    let x = infoArr1[i]
                    
                    let y = x.split(separator: "-")[0] //text
                    let z = x.split(separator: "-")[1] //bool
                    
                    var arr2 = [String]()
                    arr2.append(String(y))
                    arr2.append(String(z))

                    var zBool: Bool = false
                    if z == "t" {
                        zBool = true
                    } else if z == "f" {
                        zBool = false
                    }
                    
                    infoArr2.append(arr2)
                    
                    self.listItems.append(CreateZettelDetailViewText(text: "\(String(y))", isDone: zBool))
                    
                }
                            
            }
            
            executeThisAsyncThing = false

        }
    
    

    
    var body: some View {
        
//        listItems = changeInfoListToArray()
        

      DispatchQueue.main.async {
          if self.executeThisAsyncThing {
              self.changeInfoListToArray()
          }
      }
            
        
        return VStack {
            
            VStack {
                Text(info.name)
                   .font(.largeTitle)
                Text("\(info.day) - \(info.time)")
            }.offset(y: -50)
            
            
            List(listItems) { a in

                Button(action: self.toggle
//                    {
//
//                    if a.isDone {
//                        self.isChecked = true
//                    } else if !a.isDone {
//                        self.isChecked = false
//                    }
//
//                    print()
//                    print(a.id)
//                    print(a.text)
//                    print(a.isDone)
//                    print()
//
//                }
                ){
                    HStack {
                        Image(systemName: self.isChecked ? "checkmark.circle.fill" : "circle")
                        Text(a.text)
                    }
                }.onAppear() {
                    self.isChecked = true
                }

            }.offset(y: -50)


            Button(action: addRow) {
                Image(systemName: "plus.app.fill")
                    .offset(y: -20)
                    .font(.largeTitle)
            }




        }
        
    }
    
        private func addRow() {
                    
//            var arr = [[String]]()
//            arr = getZettelData()
//            arr.append(["ZettelName", "\(time)", "\(day)"])
//
//            let defaults = UserDefaults.standard
//            defaults.set(arr, forKey: "SavedZettelArray")

        }
    
    
}

Upvotes: 0

Views: 1506

Answers (1)

Adam VZ
Adam VZ

Reputation: 490

There's only one isChecked for the entire list. Each row is using the same variable and so when one of them is tapped, all of them change.

Based on the code it looks like each item in the list has an isDone member. Try replacing self.isChecked with a.isDone for the Image name. Then try changing the button action from self.toggle to { a.isDone.toggle() }

So you're List would look like the following.

List(listItems) { a in
    Button(action: { 
        a.isDone.toggle()
    }){
        HStack {
            Image(systemName: a.isDone ? "checkmark.circle.fill" : "circle")
            Text(a.text)
        }
    }
}.offset(y: -50)

Upvotes: 3

Related Questions