我有一个父视图,其中显示了两个子视图。请参阅附件图片。
我希望用户在View 1中输入身高和体重。当View 1中身高或体重的值发生变化时,我希望View2自动反映BMI(体重指数)的值,即体重/ (高度*高度)
对于此父视图,我尝试了多种选择,但在iOS Simulator中均无法使用
选项1
总览
@State var height: Float = 1.2
@State var weight: Float = 98.0
VStack{
View1(height : $height, weight: $weight)
View2(height : $height, weight: $weight)
}
在View1中
@Binding var height: Float
@Binding var weight: Float
TextField("Height", value: $height, formatter: NumberFormatter())
TextField("Weight", value: $weight, formatter: NumberFormatter())
在View2中
@Binding var height: Float
@Binding var weight: Float
Text("Your BMI \(calcBMI())")
private fund calcBMI(){
return height <= 0 ? 0.0 : weight / (height * height)
}
在Simulator的BMI中仅显示68.05的初始值,但是如果我更改了不会传播到View2的View1中的身高和/或体重的值,则发布此值。无论我在View1中进行什么更改,BMI都保持在68.05
问题:不是TextField的绑定应该将状态值发送回总体视图,并且View2应该从那里选择更改并在用户键入时反映BMI的最新值变化?即TextField发生了变化->影响了家长的状态?
任何线索,这里缺少什么?
选项2
我尝试将高度和重量封装在一个类中,并使其设置为ObservableObject,然后将@Published标记为高度和重量。然后,我通过总体视图将此类的相同实例注入到View1和View2中。我将View1中的高度和重量绑定到ObservedObject的instance属性,但这也没有用。从View1->父级-> View2不会传播任何更改。
import Foundation
import Combine
class BodyStats: ObservableObject{
@Published var height: Float
@Published var weight : Float
}
整体视图
@State var bodySt = BodyStats(height: 1.2, weight: 98.0)
View1(bodyST : $self.bodySt)
View2(bodyST : $self.bodySt)
View1
@ObserverdObject var bodyST : BodyStats
TextField("Height", value: $bodyST.height, formatter: NumberFormatter())
TextField("Weight", value: $bodyST.weight, formatter: NumberFormatter())
View2
@ObserverdObject var bodyST : BodyStat
Text("Your BMI \(calcBMI())")
private fund calcBMI(){
return bodyST.height <= 0 ? 0.0 : bodyST.weight / (bodyST.height * bodyST.height)
}
总体而言,我需要从View1的TextField中捕获值,然后向下传递到View 2进行实时计算(随着用户的输入)。我相信我们可以在SwiftUI中做到这一点,但无法让我了解正确的沟通方式。
答案 0 :(得分:0)
我认为原因是将计算结果完全放在单独的函数中,并且这种对渲染器的隐藏依赖性。
尝试类似以下操作(第二个选项看起来更适合您的目标)。
@ObserverdObject var bodyST : BodyStat
var body: some View {
// leave dependency on ObservedObject in body
Text("Your BMI \(calcBMI(bodyST.weight, bodyST.height))")
}
private fund calcBMI(_ weight: Float, _ height: Float) {
return height <= 0 ? 0.0 : weight / (height * height)
}
答案 1 :(得分:0)
我发现的是,如果将数据绑定到TextField的value属性,则用户在TextField中键入的内容永远不会同步到有界变量中。所以下面的行不通。
@Binding var height: Float
TextField("Height", value: @height, formatter: NumberFormatter())
下面的作品很完美
@Binding var height: String
TextField("Height", text: @height)
因此,简而言之,只要将TextField绑定到String类型的变量,我就可以在Option 1和Option 2中使用它。对我来说,这似乎是变量绑定到value:attribute时TextField绑定行为的错误。 。折衷方案是将保持变量声明为String,即使基础值是数字。
下面的总体说明是我如何使它工作
import Foundation
import Combine
class BodyStats: ObservableObject{
@Published var height: String
@Published var weight : String
func getBMI() -> Float{
if let height = Float(self.height), let weight = Float(self.weight){
return height <= 0.0 ? 0.0 : weight / (height * height)
}
return 0.0
}
整体视图
@ObservedObject var bodySt = BodyStats(height: "1.2", weight: "98.0")
View1(bodyST : bodySt)
View2(bodyST : bodySt)
在视图1中
@ObserverdObject var bodyST : BodyStats
TextField("Height", text: $bodyST.height)
TextField("Weight", text: $bodyST.weight)
在View 2中
@ObserverdObject var bodyST : BodyStat
Text("Your BMI \(bodyST.getBMI())")