ios 如何在ForEach期间从已发布的属性中检索绑定

qcbq4gxm  于 2023-07-01  发布在  iOS
关注(0)|答案(1)|浏览(70)

我有多个按钮的视图。按钮的数量是动态的,我希望能够选择它们。我有一个包含buttonViewModels的viewModel。然而,当我迭代buttonViewModels时,我无法找到正确的模式/语法来正确地更改buttonViewModels。

struct SomeView: View {
  @StateObject var viewModel: SomeViewModel
  var body: some View {
    VStack(alignment: .leading, spacing: 12) {
      ForEach(viewModel.buttonViewModels, id: \.id) { vm in
        CustomButton(isSelected: vm.$isSelected) // This is a published property, when we want a binding
      }
    }
  }
}

class SomeViewModel: ObservableObject {
  @Published var buttonViewModels: [ButtonViewModel] = []
}

class ButtonViewModel: ObservableObject {
  @Published var isSelected: Bool
  let id: String = UUID().uuidString

  init(isSelected: Bool) {
    self.isSelected = isSelected
  }
}

public struct CustomButton: View {
  @Binding public var isSelected: Bool

  public var body: some View {
    Button {
      self.isSelected.toggle()
    } label: {
      Text("\(isSelected.description)")
    }
  }
}
c6ubokkw

c6ubokkw1#

尝试这种方法,将ButtonViewModel声明为struct,并在ForEach循环中使用绑定($)。
注意,嵌套ObservableObjects不是一个好主意,这有时会在更新过程中产生问题。
有关详细信息,请参阅monitoring data

struct SomeView: View {
    @ObservedObject var viewModel: SomeViewModel  // <-- here
    
    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            ForEach($viewModel.buttonViewModels) { $vm in  // <-- here
                CustomButton(isSelected: $vm.isSelected)   // <-- here
            }
        }
    }
}

class SomeViewModel: ObservableObject {
    // for testing
    @Published var buttonViewModels: [ButtonViewModel] = [ButtonViewModel(isSelected: true),
                                                          ButtonViewModel(isSelected: true),
                                                          ButtonViewModel(isSelected: false),
                                                          ButtonViewModel(isSelected: true)]
}

struct ButtonViewModel: Identifiable {  // <-- here
    var isSelected: Bool   // <-- here
    let id: String = UUID().uuidString
    
    init(isSelected: Bool) {
        self.isSelected = isSelected
    }
}

public struct CustomButton: View {
    @Binding var isSelected: Bool
    
    public var body: some View {
        Button {
            self.isSelected.toggle()
        } label: {
            Text("\(isSelected.description)")
        }
    }
}

struct ContentView: View {
    @StateObject var viewModel = SomeViewModel()  // <-- here
    
    var body: some View {
        SomeView(viewModel: viewModel)  // <-- here
    }
}

相关问题