在 SwiftUI 中使用状态变量作为函数的输入

Posted

技术标签:

【中文标题】在 SwiftUI 中使用状态变量作为函数的输入【英文标题】:Using state variables as inputs to a func in SwiftUI 【发布时间】:2019-06-16 05:35:50 【问题描述】:

我有两个文本字段可以更改两个@State 变量的值,即startingMileage 和endingMileage,还有一个步进器可以更改名为fuelAdded 的第三个@State 变量的值。我正在尝试使用用户的输入并进行计算以计算每加仑英里数。在操场上,我的代码按预期工作。但是,它不适用于 SwiftUI 项目。

尝试在操场上运行代码如下:

func CalcMPG(start: String, end: String, fuel: Double) -> Int 
    let start = Int(start) ?? 1
    let end = Int(end) ?? 1
    let fuel = Int(fuel)
    let mpg = (end-start) / fuel
    return mpg



var endingMileage:String = "9250"
var startingMileage:String = "9000"
var fuelAdded:Double = 20

let milesPerGallon = CalcMPG(start: startingMileage, end: endingMileage, fuel: fuelAdded)
print("Fuel Efficiency: \(milesPerGallon) mpg")

这按预期工作。

struct ContentView : View 

    @State var startingMileage: String = ""
    @State var endingMileage: String = ""
    @State var fuelAdded: Double = 10
    @State var carModel: String = ""
    @State var showMPGInfo = false
    @State var milesPerGallon: Int = 10

    func CalcMPG(start: String, end: String, fuel: Double) -> Int 
        let start = Int(start) ?? 1
        let end = Int(end) ?? 1
        let fuel = Int(fuel)
        let mpg = (end-start) / fuel
        return mpg
    


    var body: some View 
        NavigationView 
            VStack
                HStack 
                    Text("Car Model:")
                    Spacer()
                    TextField($carModel, placeholder: Text("Toyota Corolla"))
                        .textFieldStyle(.roundedBorder)
                
                HStack 
                    Text("Starting ODO:")
                    Spacer()
                    TextField($startingMileage, placeholder: Text("8000"))
                    .textFieldStyle(.roundedBorder)
                    Text("miles")
                

                HStack 
                    Text("Ending ODO:")
                    Spacer()
                    TextField($endingMileage, placeholder: Text("9000"))
                        .textFieldStyle(.roundedBorder)
                    Text("miles")
                
                HStack 
                    Stepper(value: $fuelAdded, in: 0...20, step: 0.5) 
                        Text("Fuel Added: \(fuelAdded, specifier: "%0.1f") gallons")
                    
                
                Button(action: 
                    self.showMPGInfo.toggle() )
                        Text("Show/Hide MPG")
                
                    if showMPGInfo 
                        Spacer()
                        milesPerGallon = CalcMPG(start: startingMileage, end: endingMileage, fuel: fuelAdded)
                        Text("Fuel effiency: \(milesPerGallon) MPG")
                            .font(.largeTitle)
                    
                .padding()
                .navigationBarTitle(Text("Gas Mileage Calculator"))
        
    

当用户点击“显示/隐藏 MPG”时。我希望最终生成的文本是“燃料效率:xx MPG”

但是,我收到以下错误:

ContentView.swift:34:19:无法推断复杂的闭包返回类型;添加显式类型以消除歧义

它对我来说没有任何意义...它突出显示 NavigationView 中的起始 VStack。

有什么想法吗?

【问题讨论】:

好的,这一定与milesPerGallon = CalcMPG(...) 的声明有关,因为只要我把它拿出来并把 (CalcMPG(...)) 放入我想要返回的文本中它可以按需要工作。有人知道我在这里做错了什么吗?在这种情况下使用 @State 变量是不是不对? 【参考方案1】:

问题在于milesPerGallon 的赋值不能很好地与用于构建视图层次结构参数的“函数构建器语法”一起使用。如果我们将@State var milesPerGallon 替换为局部变量(即is,它不携带视图所依赖的状态,只有一个中间值),就会变得更加明显:

if showMPGInfo 
    Spacer()
    let milesPerGallon = CalcMPG(start: startingMileage,
                                 end: endingMileage, fuel: fuelAdded)
    Text("Fuel effiency: \(milesPerGallon) MPG")
        .font(.largeTitle)

现在编译错误是

包含声明的闭包不能与函数生成器“ViewBuilder”一起使用

有关函数构建器语法的更多信息,请参阅What enables SwiftUI's DSL?(其中还包含指向文档的链接)。

最简单的解决方案是避免使用局部变量并直接插入文本:

if showMPGInfo 
    Spacer()
    Text("Fuel effiency: \(CalcMPG(start: startingMileage, end: endingMileage, fuel: fuelAdded)) MPG")
        .font(.largeTitle)

其他解决方案是在“立即评估的闭包”中计算文本字段:

if showMPGInfo 
    Spacer();
     () -> Text in
        let milesPerGallon = CalcMPG(start: startingMileage,
                                      end: endingMileage,
                                      fuel: fuelAdded)
        return Text("Fuel effiency: \(milesPerGallon) MPG")
    ()
    .font(.largeTitle)

或者定义一个辅助函数

func resultField(start: String, end: String, fuel: Double) -> Text 
    let  milesPerGallon = CalcMPG(start: startingMileage, end: endingMileage, fuel: fuelAdded)
    return Text("Fuel effiency: \(milesPerGallon) MPG")

并将其用作

if showMPGInfo 
    Spacer()
    resultField(start: startingMileage, end: endingMileage,
                fuel: fuelAdded)
        .font(.largeTitle)

可能还有其他解决方法,但这是我目前想到的。

【讨论】:

以上是关于在 SwiftUI 中使用状态变量作为函数的输入的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI TextField 数字输入

SwiftUI Picker 在同一视图中更改第二个状态变量

在 SwiftUI 中更新 CoreData 时更新状态变量

如何在swiftui中的视图之间传递变量?

SwiftUI,不能从委托回调中更改状态? (附代码)

在主体外访问 SwiftUI 视图中的状态变量