Mvvm 什么';让多个SwiftUI视图能够相互更新的惯用方法是什么?
我是一个iOS和UI新手,为我女儿编写了一个简单的应用程序,帮助她制作柠檬水。三个滑块控制配料(水、糖、柠檬),两个滑块控制口味参数(糖醋)。其想法是,对于给定的甜度和酸度,调整任何成分滑块将更新其他滑块,以满足指定的甜度和酸度。您可以看到以下效果: 正如你所看到的,我已经让它工作了,但这不是一个很好的解决方案;视图中的一切都是以一种非常迫切的方式发生的,滑块值的更改驱动了对Mvvm 什么';让多个SwiftUI视图能够相互更新的惯用方法是什么?,mvvm,swiftui,Mvvm,Swiftui,我是一个iOS和UI新手,为我女儿编写了一个简单的应用程序,帮助她制作柠檬水。三个滑块控制配料(水、糖、柠檬),两个滑块控制口味参数(糖醋)。其想法是,对于给定的甜度和酸度,调整任何成分滑块将更新其他滑块,以满足指定的甜度和酸度。您可以看到以下效果: 正如你所看到的,我已经让它工作了,但这不是一个很好的解决方案;视图中的一切都是以一种非常迫切的方式发生的,滑块值的更改驱动了对updateIngredients()的调用 我希望有一个视图模型句柄来确定要显示的值,一个模型在每次滑块值更改时处理成
updateIngredients()
的调用
我希望有一个视图模型句柄来确定要显示的值,一个模型在每次滑块值更改时处理成分的重新计算,但我无法弄清楚如何重新计算所有成分而不陷入无限循环
我已使视图模型可观察
并发布了其属性,并将这些属性绑定到滑块值。这很好。为了简单起见,我将跳过模型并将成分重新计算放在视图模型中:
struct ContentView: View {
@ObservedObject var display: DisplayCalculator
...
VStack {
Text("Lemons: \(display.numLemons, specifier: "%.0f")")
Slider(value: $display.numLemons, in: display.lemons["minValue"]!...display.lemons["maxValue"]!, step: display.lemons["step"]!)
...
}
// View Model
class DisplayCalculator: ObservableObject {
// Initial state recipe is 200g sugar, 1400ml water, 7 lemons
@Published var numLemons: Double = 7
@Published var sugarWeight: Double = 200
@Published var waterWeight: Double = 1400
@Published var lemonWaterRatio: Double = 7/1400
@Published var sugarWaterRatio: Double = 200/1400
let lemons: Dictionary<String, Double> = [ "minValue": 0, "maxValue": 40, "step": 1]
...
// How can I call this?
func updateIngredients(_ ingredient: String) {
switch(ingredient) {
case "lemons":
// Set self.sugarWeight and self.waterWeight based on self.lemonWaterRatio and self.sugarWaterRatio
...
}
}
...
}
struct ContentView:View{
@观察对象变量显示:DisplayCalculator
...
VStack{
文本(“柠檬:\(display.numLemons,说明符:%.0f”))
滑块(值:$display.numLemons,in:display.lemons[“minValue”]!…display.lemons[“maxValue”]!,step:display.lemons[“step”!)
...
}
//视图模型
类DisplayCalculator:ObservableObject{
//初始配方为200g糖、1400ml水、7个柠檬
@已发布变量numLemons:Double=7
@发布重量:双倍=200
@公布重量:双=1400
@公布变量lemonWaterRatio:Double=7/1400
@公布的var糖水比:双=200/1400
lemons:Dictionary=[“minValue”:0,“maxValue”:40,“step”:1]
...
//我怎么称呼这个?
func更新元素(uu成分:字符串){
开关(成分){
案例“柠檬”:
//根据self.lemonWaterRatio和self.sugarWaterRatio设置self.sugarWeight和self.waterWeight
...
}
}
...
}
我遇到的问题是,每次其中一个值发生更改时,我都需要重新计算整个值集。我知道触发重新计算的唯一方法是从发布的属性上的willSet
驱动它。但是所有属性都需要willSet
,因此当重新计算更新所有其他值时,那些珀蒂观察者无限触发
有没有可能让任何一个滑块能够更新所有其他滑块,而无需从滑块本身驱动计算?这里是一种可能的方法
.signature(TapSignature().onEnded())
。这个函数调用函数,然后更新您的值
struct ContentView: View {
@ObservedObject var display: DisplayCalculator = DisplayCalculator()
var body: some View {
VStack() {
Text("Lemons: \(display.numLemons, specifier: "%.0f")")
Slider(value: $display.numLemons, in: display.lemons["minValue"]!...display.lemons["maxValue"]!, step: display.lemons["step"]!).gesture(TapGesture().onEnded({_ in
self.display.updateValues(ingredient: Ingredients.numLemons)
}))
Text("Sugar: \(display.sugarWeight, specifier: "%.0f")")
Slider(value: $display.sugarWeight, in: 0...2000, step: 10).gesture(TapGesture().onEnded({_ in
self.display.updateValues(ingredient: Ingredients.sugarWeight)
}))
Text("Water: \(display.waterWeight, specifier: "%.0f")")
Slider(value: $display.waterWeight, in: 0...5000, step: 50).gesture(TapGesture().onEnded({_ in
self.display.updateValues(ingredient: Ingredients.waterWeight)
}))
}.padding()
}
}
class DisplayCalculator: ObservableObject {
@Published var numLemons: Double = Ingredients.numLemons.rawValue
@Published var sugarWeight: Double = Ingredients.sugarWeight.rawValue
@Published var waterWeight: Double = Ingredients.waterWeight.rawValue
let lemons: Dictionary<String, Double> = [ "minValue": 0, "maxValue": 40, "step": 1]
func updateValues(ingredient: Ingredients) {
switch ingredient {
case .numLemons :
self.waterWeight = self.numLemons/IngredientsMultiplier.lemonWaterRatio.rawValue
self.sugarWeight = self.waterWeight*IngredientsMultiplier.sugarWaterRatio.rawValue
case .sugarWeight:
//do the math
print("do the math")
case .waterWeight:
//do the math
print("do the math")
}
}
}
enum Ingredients: Double {
// Initial state recipe is 200g sugar, 1400ml water, 7 lemons
case numLemons = 7
case sugarWeight = 200
case waterWeight = 1400
}
enum IngredientsMultiplier: Double {
case lemonWaterRatio = 0.005 //7/1400
case sugarWaterRatio = 0.1428 //200/1400
}
struct ContentView:View{
@ObservedObject变量显示:DisplayCalculator=DisplayCalculator()
var body:一些观点{
VStack(){
文本(“柠檬:\(display.numLemons,说明符:%.0f”))
滑块(值:$display.numLemons,in:display.lemons[“minValue”]!…display.lemons[“maxValue”]!,step:display.lemons[“step”!)。手势(点击手势().oneded({uu)in
self.display.updateValue(配料:配料.numLemons)
}))
文本(“糖:\(display.sugarWeight,说明符:%.0f”))
滑块(值:$display.sugarWeight,in:0…2000,步数:10)。手势(Tap手势().oneded({uuin
self.display.updateValue(配料:配料.糖重)
}))
文本(“水:\(display.waterWeight,说明符:%.0f”))
滑块(值:$display.waterWeight,in:0…5000,步长:50)
self.display.updateValue(配料:配料.水重)
}))
}.padding()
}
}
类DisplayCalculator:ObservableObject{
@已发布的变量numLemons:Double=components.numLemons.rawValue
@发布的var sugarWeight:Double=配料.sugarWeight.rawValue
@已发布变量waterWeight:Double=配料.waterWeight.rawValue
lemons:Dictionary=[“minValue”:0,“maxValue”:40,“step”:1]
func更新值(成分:成分){
开关元件{
案例.努姆莱蒙斯:
self.waterWeight=self.numLemons/IngredientsMultiplier.lemonWaterRatio.rawValue
self.sugarWeight=self.waterWeight*IngredientsMultiplier.sugarWaterRatio.rawValue
例.糖重:
//算算
打印(“计算”)
案例.水重:
//算算
打印(“计算”)
}
}
}
枚举成分:双份{
//初始配方为200g糖、1400ml水、7个柠檬
案例numLemons=7
箱重=200
箱水重量=1400
}
枚举IngCreditsMultiplier:双精度{
案例柠檬水比率=0.005//7/1400
案例糖水比=0.1428//200/1400
}
看起来像这样:
我希望这有帮助
但是所有属性都需要设置willSet,因此当重新计算更新所有其他值时,这些属性将被触发
struct ContentView: View {
@ObservedObject var display: DisplayCalculator = DisplayCalculator()
var body: some View {
VStack() {
Text("Lemons: \(display.numLemons, specifier: "%.0f")")
Slider(value: $display.numLemons, in: display.lemons["minValue"]!...display.lemons["maxValue"]!, step: display.lemons["step"]!).gesture(TapGesture().onEnded({_ in
self.display.updateValues(ingredient: Ingredients.numLemons)
}))
Text("Sugar: \(display.sugarWeight, specifier: "%.0f")")
Slider(value: $display.sugarWeight, in: 0...2000, step: 10).gesture(TapGesture().onEnded({_ in
self.display.updateValues(ingredient: Ingredients.sugarWeight)
}))
Text("Water: \(display.waterWeight, specifier: "%.0f")")
Slider(value: $display.waterWeight, in: 0...5000, step: 50).gesture(TapGesture().onEnded({_ in
self.display.updateValues(ingredient: Ingredients.waterWeight)
}))
}.padding()
}
}
class DisplayCalculator: ObservableObject {
@Published var numLemons: Double = Ingredients.numLemons.rawValue
@Published var sugarWeight: Double = Ingredients.sugarWeight.rawValue
@Published var waterWeight: Double = Ingredients.waterWeight.rawValue
let lemons: Dictionary<String, Double> = [ "minValue": 0, "maxValue": 40, "step": 1]
func updateValues(ingredient: Ingredients) {
switch ingredient {
case .numLemons :
self.waterWeight = self.numLemons/IngredientsMultiplier.lemonWaterRatio.rawValue
self.sugarWeight = self.waterWeight*IngredientsMultiplier.sugarWaterRatio.rawValue
case .sugarWeight:
//do the math
print("do the math")
case .waterWeight:
//do the math
print("do the math")
}
}
}
enum Ingredients: Double {
// Initial state recipe is 200g sugar, 1400ml water, 7 lemons
case numLemons = 7
case sugarWeight = 200
case waterWeight = 1400
}
enum IngredientsMultiplier: Double {
case lemonWaterRatio = 0.005 //7/1400
case sugarWaterRatio = 0.1428 //200/1400
}
var lemons = 0 { willSet { if newValue != lemons {updateIngredients("lemon")}}}
var sugar = 0 { willSet { if newValue != sugar {updateIngredients("sugar")}}}