SwiftUI - 刷新视图模型数组中更新的模型视图
SwiftUI - Refresh view on model updated in view model array
要问的问题很简单,但我可能忘记了代码中的某些内容。
让我们用一张图片更好地解释一下:
我基本上需要更新“COUNT”和“PRICE”,而 selecting/deselecting 项。
我有这样的代码结构:
型号:
class ServiceSelectorModel: Identifiable, ObservableObject {
var id = UUID()
var serviceName: String
var price: Double
init(serviceName: String, price: Double) {
self.serviceName = serviceName
self.price = price
}
@Published var selected: Bool = false
}
ViewModel:
class ServiceSelectorViewModel: ObservableObject {
@Published var services = [ServiceSelectorModel]()
init() {
self.services = [
ServiceSelectorModel(serviceName: "SERVICE 1", price: 1.80),
ServiceSelectorModel(serviceName: "SERVICE 2", price: 10.22),
ServiceSelectorModel(serviceName: "SERVICE 3", price: 2.55)
]
}
}
切换视图
struct ServiceToggleView: View {
@ObservedObject var model: ServiceSelectorModel
var body: some View {
VStack(alignment: .center) {
HStack {
Text(model.serviceName)
Toggle(isOn: $model.selected) {
Text(String(format: "€ +%.2f", model.price))
.frame(maxWidth: .infinity, alignment: .trailing)
}
}
.background(model.selected ? Color.yellow : Color.clear)
}
}
}
ServiceSelectorView
struct ServiceSelectorView: View {
@ObservedObject var serviceSelectorVM = ServiceSelectorViewModel()
var body: some View {
VStack {
VStack(alignment: .leading) {
ForEach (serviceSelectorVM.services, id: \.id) { service in
ServiceToggleView(model: service)
}
}
let price = serviceSelectorVM.services.filter{ [=13=].selected }.map{ [=13=].price }.reduce(0, +)
Text("SELECTED: \(serviceSelectorVM.services.filter{ [=13=].selected }.count)")
Text(String(format: "TOTAL PRICE: €%.2f", price))
}
}
}
在此代码中,我能够更新模型的 selected
状态,但包含所有模型的视图模型应该刷新 PRICE
不更新.
似乎数组中的模型没有改变。
我忘记了什么?
可能最简单的方法是将您的模型设为值类型,然后更改其属性,持有它的视图模型将被更新。并更新视图以使用绑定到这些值
struct ServiceSelectorModel: Identifiable {
var id = UUID()
var serviceName: String
var price: Double
init(serviceName: String, price: Double) {
self.serviceName = serviceName
self.price = price
}
var selected: Bool = false
}
struct ServiceToggleView: View {
@Binding var model: ServiceSelectorModel
...
}
...
ForEach (serviceSelectorVM.services.indices, id: \.self) { i in
ServiceToggleView(model: $serviceSelectorVM.services[i])
}
注意:内联编写,未经测试,可能需要修复一些错字
如果您仔细观察,您已经创建了两个不同的单一事实来源。这就是 parent 没有更新的原因,因为它没有链接到 child。
一种方法是将 ServiceSelectorModel
创建为结构,并在 child 视图中将 services
数组作为 @Binding
传递。下面是工作示例。
ViewModel-:
struct ServiceSelectorModel {
var id = UUID().uuidString
var serviceName: String
var price: Double
var isSelected:Bool = false
init(serviceName: String, price: Double) {
self.serviceName = serviceName
self.price = price
}
}
class ServiceSelectorViewModel: ObservableObject,Identifiable {
@Published var services = [ServiceSelectorModel]()
var id = UUID().uuidString
init() {
self.services = [
ServiceSelectorModel(serviceName: "SERVICE 1", price: 1.80),
ServiceSelectorModel(serviceName: "SERVICE 2", price: 10.22),
ServiceSelectorModel(serviceName: "SERVICE 3", price: 2.55)
]
}
}
观看次数-:
struct ServiceToggleView: View {
@Binding var model: [ServiceSelectorModel]
var body: some View {
VStack(alignment: .center) {
ForEach(0..<model.count) { index in
HStack{
Text(model[index].serviceName)
Toggle(isOn: $model[index].isSelected) {
Text(String(format: "€ +%.2f", model[index].price))
.frame(maxWidth: .infinity, alignment: .trailing)
}
}.background(model[index].isSelected ? Color.yellow : Color.clear)
}
}
}
}
struct ServiceSelectorView: View {
@ObservedObject var serviceSelectorVM = ServiceSelectorViewModel()
var body: some View {
VStack {
VStack(alignment: .leading) {
ServiceToggleView(model: $serviceSelectorVM.services)
}
let price = serviceSelectorVM.services.filter{ [=11=].isSelected }.map{ [=11=].price }.reduce(0, +)
Text("SELECTED: \(serviceSelectorVM.services.filter{ [=11=].isSelected }.count)")
Text(String(format: "TOTAL PRICE: €%.2f", price))
}
}
}
要问的问题很简单,但我可能忘记了代码中的某些内容。
让我们用一张图片更好地解释一下:
我基本上需要更新“COUNT”和“PRICE”,而 selecting/deselecting 项。
我有这样的代码结构:
型号:
class ServiceSelectorModel: Identifiable, ObservableObject {
var id = UUID()
var serviceName: String
var price: Double
init(serviceName: String, price: Double) {
self.serviceName = serviceName
self.price = price
}
@Published var selected: Bool = false
}
ViewModel:
class ServiceSelectorViewModel: ObservableObject {
@Published var services = [ServiceSelectorModel]()
init() {
self.services = [
ServiceSelectorModel(serviceName: "SERVICE 1", price: 1.80),
ServiceSelectorModel(serviceName: "SERVICE 2", price: 10.22),
ServiceSelectorModel(serviceName: "SERVICE 3", price: 2.55)
]
}
}
切换视图
struct ServiceToggleView: View {
@ObservedObject var model: ServiceSelectorModel
var body: some View {
VStack(alignment: .center) {
HStack {
Text(model.serviceName)
Toggle(isOn: $model.selected) {
Text(String(format: "€ +%.2f", model.price))
.frame(maxWidth: .infinity, alignment: .trailing)
}
}
.background(model.selected ? Color.yellow : Color.clear)
}
}
}
ServiceSelectorView
struct ServiceSelectorView: View {
@ObservedObject var serviceSelectorVM = ServiceSelectorViewModel()
var body: some View {
VStack {
VStack(alignment: .leading) {
ForEach (serviceSelectorVM.services, id: \.id) { service in
ServiceToggleView(model: service)
}
}
let price = serviceSelectorVM.services.filter{ [=13=].selected }.map{ [=13=].price }.reduce(0, +)
Text("SELECTED: \(serviceSelectorVM.services.filter{ [=13=].selected }.count)")
Text(String(format: "TOTAL PRICE: €%.2f", price))
}
}
}
在此代码中,我能够更新模型的 selected
状态,但包含所有模型的视图模型应该刷新 PRICE
不更新.
似乎数组中的模型没有改变。
我忘记了什么?
可能最简单的方法是将您的模型设为值类型,然后更改其属性,持有它的视图模型将被更新。并更新视图以使用绑定到这些值
struct ServiceSelectorModel: Identifiable {
var id = UUID()
var serviceName: String
var price: Double
init(serviceName: String, price: Double) {
self.serviceName = serviceName
self.price = price
}
var selected: Bool = false
}
struct ServiceToggleView: View {
@Binding var model: ServiceSelectorModel
...
}
...
ForEach (serviceSelectorVM.services.indices, id: \.self) { i in
ServiceToggleView(model: $serviceSelectorVM.services[i])
}
注意:内联编写,未经测试,可能需要修复一些错字
如果您仔细观察,您已经创建了两个不同的单一事实来源。这就是 parent 没有更新的原因,因为它没有链接到 child。
一种方法是将 ServiceSelectorModel
创建为结构,并在 child 视图中将 services
数组作为 @Binding
传递。下面是工作示例。
ViewModel-:
struct ServiceSelectorModel {
var id = UUID().uuidString
var serviceName: String
var price: Double
var isSelected:Bool = false
init(serviceName: String, price: Double) {
self.serviceName = serviceName
self.price = price
}
}
class ServiceSelectorViewModel: ObservableObject,Identifiable {
@Published var services = [ServiceSelectorModel]()
var id = UUID().uuidString
init() {
self.services = [
ServiceSelectorModel(serviceName: "SERVICE 1", price: 1.80),
ServiceSelectorModel(serviceName: "SERVICE 2", price: 10.22),
ServiceSelectorModel(serviceName: "SERVICE 3", price: 2.55)
]
}
}
观看次数-:
struct ServiceToggleView: View {
@Binding var model: [ServiceSelectorModel]
var body: some View {
VStack(alignment: .center) {
ForEach(0..<model.count) { index in
HStack{
Text(model[index].serviceName)
Toggle(isOn: $model[index].isSelected) {
Text(String(format: "€ +%.2f", model[index].price))
.frame(maxWidth: .infinity, alignment: .trailing)
}
}.background(model[index].isSelected ? Color.yellow : Color.clear)
}
}
}
}
struct ServiceSelectorView: View {
@ObservedObject var serviceSelectorVM = ServiceSelectorViewModel()
var body: some View {
VStack {
VStack(alignment: .leading) {
ServiceToggleView(model: $serviceSelectorVM.services)
}
let price = serviceSelectorVM.services.filter{ [=11=].isSelected }.map{ [=11=].price }.reduce(0, +)
Text("SELECTED: \(serviceSelectorVM.services.filter{ [=11=].isSelected }.count)")
Text(String(format: "TOTAL PRICE: €%.2f", price))
}
}
}