gpt4 book ai didi

SwiftUI ViewModel 不更新计算变量

转载 作者:行者123 更新时间:2023-11-28 11:24:39 25 4
gpt4 key购买 nike

我有一个 SwiftUI View 类,它能够在用户更新具有可绑定(bind)值的 TextField 时更新自己的 Text View 。问题是所有变量都包含在 View 类本身中。一旦我将变量提取到 View 模型类中,计算字段就不再随着可绑定(bind)值的更新而更新。这是(非更新)代码:

struct KeView: View {
var vm = KeViewModel()

var body: some View {
return VStack {
Image("ke")
InputFieldView(category: Localizable.weaponAp(), input: vm.$ap)
InputFieldView(category: Localizable.targetArmor(), input: vm.$targetArmor)
InputFieldView(category: Localizable.weaponRange(), input: vm.$weaponRange)
InputFieldView(category: Localizable.targetRange(), input: vm.$targetRange)
Text(vm.damageString)
.foregroundColor(Color.white)
.padding()
.background(vm.damageColor)
.frame(maxHeight: .infinity)
}
}
}


struct KeView_Previews: PreviewProvider {
static var previews: some View {
KeView()
}
}

struct KeViewModel {
@State var ap = ""
@State var targetArmor = ""
@State var targetRange = ""
@State var weaponRange = ""

var damageColor: Color {
if damageString.contains(Localizable.outOfRange()) { return Color.red }
if damageString.contains(Localizable.inefficient()) { return Color.black }
let d = damageString.split(separator: " ").last ?? ""
if (Double(d) ?? 0) < 10 { return Color.blue }
return Color.red
}

var damageString : String {
guard let ap = Double(ap),
let weaponRange = Double(weaponRange),
let targetRange = Double(targetRange),
let targetArmor = Double(targetArmor) else {
return Localizable.damagePrefix() + " 0"
}
if (weaponRange < targetRange){
return Localizable.outOfRange()
} else {
let difference = (weaponRange - targetRange) / 175
//print("Difference is equal to",difference)
let actualAp = ap + difference
//print("actual AP is equal to",actualAp)
if (actualAp < targetArmor){
return Localizable.inefficient()
} else if (targetArmor == 0){
return Localizable.damagePrefix()
+ "\(round(actualAp * 2))"
} else {
return Localizable.damagePrefix()
+ " \(round((actualAp - Double(targetArmor)) / 2 + 1.0))"
}
}
}
}

下面是能够在用户输入值时更新的代码:

struct KeView: View {
@State var ap = ""
@State var targetArmor = ""
@State var targetRange = ""
@State var weaponRange = ""

var damageColor: Color {
if damageString.contains(Localizable.outOfRange()) { return Color.red }
if damageString.contains(Localizable.inefficient()) { return Color.black }
let d = damageString.split(separator: " ").last ?? ""
if (Double(d) ?? 0) < 10 { return Color.blue }
return Color.red
}

var damageString : String {
guard let ap = Double(ap),
let weaponRange = Double(weaponRange),
let targetRange = Double(targetRange),
let targetArmor = Double(targetArmor) else {
return Localizable.damagePrefix() + " 0"
}
if (weaponRange < targetRange){
return Localizable.outOfRange()
} else {
let difference = (weaponRange - targetRange) / 175
//print("Difference is equal to",difference)
let actualAp = ap + difference
//print("actual AP is equal to",actualAp)
if (actualAp < targetArmor){
return Localizable.inefficient()
} else if (targetArmor == 0){
return Localizable.damagePrefix()
+ "\(round(actualAp * 2))"
} else {
return Localizable.damagePrefix()
+ " \(round((actualAp - Double(targetArmor)) / 2 + 1.0))"
}
}
}

var body: some View {
return VStack {
Image("ke")
InputFieldView(category: Localizable.weaponAp(), input: $ap)
InputFieldView(category: Localizable.targetArmor(), input: $targetArmor)
InputFieldView(category: Localizable.weaponRange(), input: $weaponRange)
InputFieldView(category: Localizable.targetRange(), input: $targetRange)
Text(String(self.damageString))
.foregroundColor(Color.white)
.padding()
.background(damageColor)
.frame(maxHeight: .infinity)
}
}
}


struct KeView_Previews: PreviewProvider {
static var previews: some View {
KeView()
}
}

这似乎很愚蠢,因为我无法将这些变量提取到外部结构并且更愿意在我的数据和我的 View 之间进行清晰的分离。任何帮助表示赞赏。最后,如果您想自己构建和运行该项目,可以在 https://github.com/jamesjmtaylor/wrd-ios 获得完整的项目。

最佳答案

将您的 KeViewModel 结构更改为满足 ObservableObject 协议(protocol)的类。此外,将 @State 属性包装器更改为 @Published 属性包装器,如下所示:

class KeViewModel: ObservableObject {
@Published var ap = ""
@Published var targetArmor = ""
@Published var targetRange = ""
@Published var weaponRange = ""

同时使用@ObservedOjbect 属性包装器标记您的 ViewModel 实例:

@ObservedObject var vm: KeViewModel

现在您通过 TabView 中的构造函数将此 View 模型注入(inject)到特定 View :

TabView {
KeView(vm: KeViewModel()).tabItem {
Text("KE")
Image("first")
...

在内容预览中:

struct KeView_Previews: PreviewProvider {
static var previews: some View {
KeView(vm: KeViewModel())
}
}

现在您的 View 可以观察 ViewModel 对象以发布 ViewModel 对象属性的新值,而无需将其作为环境对象向下提供到 View 层次结构,但仍会自动在所有必要的位置获取更新。

关于SwiftUI ViewModel 不更新计算变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58607798/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com