1 Reply
      Latest reply on Nov 8, 2019 2:00 PM by keaura
      sorin36 Level 1 Level 1 (0 points)

        I'm using a ForEach to parse a list of models and create a view for each of them, Each view contains a Button and a Text, the Button toggles a visibility state which should hide the text and change the Button's title (Invisible/Visible).

        struct ContentView: View {
            
            @State var colors: [MyColor] = [MyColor(val: "Blue"), MyColor(val: "Yellow"), MyColor(val: "Red")]
            
            var body: some View {
                
                ForEach(colors, id: \.uuid) { color in
                    ButtonColorView(color: color.val)
                }
                
            }
        }
        
        struct ButtonColorView: View {
            
            var color: String
            
            @State var visible = true
            
            var body: some View {
                
                if visible {
                    return AnyView(  HStack {
                        Button("Invisible") {
                            self.visible.toggle()
                        }
                        Text(color)
                    })
                } else {
                    return AnyView(
                        Button("Visible") {
                            self.visible.toggle()
                        }
                    )
                }
            }
        }
        
        
        
        class MyColor: Identifiable {
            let uuid = UUID()
            let val: String
            
            init(val: String) {
                self.val = val
            }
        }

        Unfortunately it's not working, the views inside the ForEach do not change when the Button is pressed. I replaced the Foreach with ButtonColorView(color: colors[0].val) and it seems to work, so I'd say the problem is at ForEach.

        I also tried breakpoints in ButtonColorView and it seems the view is called when the Button is triggered returning the right view, anyways the view does not update on screen.

        So, am I using the ForEach in a wrong way ?

        This problem occurs in a more complex app, but I tried to extract it in this small example.

         

        To summarize it: I need ButtonColorView to return different Views depending of its state (visibility in this case)

         

         

        PS: I'm using Xcode 11 Beta 6

        • Re: Views do not update inside the ForEach in SwiftUI
          keaura Level 1 Level 1 (0 points)

          I am having a similar problem with Picker:

           

          class Category: Identifiable {
              let uuid = UUID()
              let label: String
              init (_ label: String) {
                  self.label = label
              }
          }
          
          class SessionModel: ObservableObject {
              let didChange = PassthroughSubject<Void, Never>()
              
              @Published var categories: [Category] = [Category("Home"), Category("Work"), Category("Financial"), Category("Entertainmen")]
              @Published var categoryIndex = 0
              
              func selectedCategory() -> String {
                  categories[categoryIndex].label
              }
              
              func addCategory(_ newCategory: String) {
                  categories.append(Category(newCategory))
                  didChange.send()
              }
          }
          
          // usage
                         Picker(
                              selection: self.$viewModel.categoryIndex,
                              label: Text("Colors")
                          ) {
                              ForEach(self.viewModel.categories) { category in
                                  Text(category.label)
                              }
                          }
                          .pickerStyle(WheelPickerStyle())
          

           

          If you change the model (self.viewModel.addCategory("New Item"))  the ForEach will not trigger. I don't know what else to do.