0

Hello i have an issue with the refresh of my view when i toggle a boolean. Here is the code

class MyItem: Identifiable {
   @Published var isActive: Bool
}

struct myView: View {
   @Binding var item: MyItem
   var body: some View {
      HStack {
         Toggle("", isOn: $item.isActive)
         Spacer()
         TextField("", text: item.isActive ? $text : .constant("")) { isFocused in
             guard !isFocused && text.count == 0 else { return }
             item.isActive.toggle
         }
            .background(item.isActive ? Color.white : Color.clear)
      }
   }
}

when i lose my focus and run item.isActive.toggle it change correctly his value, but my Toggle and my TextField doesn't update their UI (the Toggle is still active and the background of the TextField is still white)

Any idea of what i am missing ?

  • In context of SwiftUI Published works only in ObservableObject which is wrapped in ObservedObject in view. Find some tutorial by key words. – Asperi Jun 10 '22 at 09:31
  • How do you supply the binding from the superview? – Paulw11 Jun 10 '22 at 09:35

1 Answers1

1

Binding only updates the view when the wrapped value is updated. However, since your wrapped value is a class, not a struct, the view would only be updated if you replaced the instance with another one, not if you updated a property of the instance.

You need to make MyItem conform to ObservableObject and use @ObservedObject or @StateObject on your view, then it will be updated correctly.

class MyItem: ObservableObject {
   @Published var isActive: Bool
}

struct myView: View {
   @ObservedObject private var item: MyItem

   init(item: MyItem) {
       self.item = item
   }

   var body: some View {
      HStack {
         Toggle("", isOn: $item.isActive)
         Spacer()
         TextField("", text: item.isActive ? $text : .constant("")) { isFocused in
             guard !isFocused && text.count == 0 else { return }
             item.isActive.toggle
         }
            .background(item.isActive ? Color.white : Color.clear)
      }
   }
}
Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
  • Ok, but i have to keep `@Binding private var item: MyItem` because `myView ` is used as an item list which will update his parent's viewModel. `ForEach($viewModel.items) { $item in MyView(item: $item) }` – Gauthier Beignie Jun 10 '22 at 09:50
  • @user3227545 no, you don't. You can get a `Binding` from an `ObservedObject` using the same `$` syntax and everything will work perfectly. – Dávid Pásztor Jun 10 '22 at 09:52
  • After some tests in works just fine. On my parent view my array of item is up to date when i check on click on a button. In addition i am looking for a way to catch update of the item in my parent via the array of item. have you an idea for that ? – Gauthier Beignie Jun 10 '22 at 15:24
  • @GauthierBeignie you mean you want to update the parent view itself when any item updates? [This](https://stackoverflow.com/a/58996712/4667835) answer explains how to propagate changes from child `ObservableObject`s to their parents. – Dávid Pásztor Jun 10 '22 at 15:30