SwiftUI:WeSplit项目 计算每个人的金额

2020-03-25 17:53:50 浏览数 (1)

到目前为止,最后一部分显示了一个简单的文本视图,其中包含用户输入的任何账单金额,但现在是该项目重要部分的时候了:我们希望该文本视图显示每个人需要为账单支付多少。

有几种方法可以解决这个问题,但最简单的方法恰好也是最干净的方法,我的意思是它给了我们清晰易懂的代码:我们将添加一个计算总数的计算属性。

这需要做少量的数学运算:每人应支付的总金额等于订单价值加小费百分比除以人数。

但在我们做这件事之前,我们首先需要找出有多少人,小费百分比是多少,以及订单的价值。听起来很简单,但有一些小问题:

  • 正如您已经看到的,numberOfPeople被设置为了2——当它存储值3时,意味着5个人。
  • tipPercentage整数在tipPercentages数组中存储索引,而不是实际的tip百分比。
  • checkAmount属性是用户输入的字符串,可能是20这样的有效数字,也可能是“fish”这样的字符串,甚至可能是空的。

所以,我们将创建一个新的计算属性totalPerPerson,它将是一个Double,它将从上面的三个值开始。

首先,在body属性之前添加计算属性:

代码语言:javascript复制
var totalPerPerson: Double {
    // calculate the total per person here
    return 0
}

它将返回0,这样代码就不会崩溃,但是我们将用我们的计算替换//calculate the total per person here注释。

接下来,我们可以通过读取numberOfPeople并添加2来计算出有多少人。记住,这个值的范围是2到100,但它是从0开始计算的,所以我们需要添加2。

所以,首先用以下内容替换//calculate the total per person here

代码语言:javascript复制
let peopleCount = Double(numberOfPeople   2)

您会注意到,将结果值转换为Double,这样我们就可以将所有内容相加并将其除以,而不会失去准确性。

接下来我们需要计算出实际的小费百分比。我们的tipPercentage属性存储用户选择的值,但实际上这只是tipPercentages数组中的一个索引。因此,我们需要查看tipPercentages以确定他们选择了什么,然后再次将其转换为Double,这样我们就可以保持所有精度——将其添加到前一行下面:

代码语言:javascript复制
let tipSelection = Double(tipPercentages[tipPercentage])

我们需要计算的最后一个数字是他们账单的金额。现在,如果您还记得这实际上是一个字符串,因为它被用作对文本输入框的双向绑定。尽管我们编写代码只显示十进制键盘,但没有什么可以阻止创造性用户在其中输入无效值,因此我们需要小心处理。

我们想要的另一个Double是账单金额。实际上,我们有一个字符串可能包含也可能不包含有效的Double:它可能是22.50,可能是空字符串,也可能是莎士比亚的全部作品。它是一根绳子,几乎可以是任何东西。

幸运的是,Swift有一个将字符串转换为Double的简单方法,它看起来如下:

代码语言:javascript复制
let stringValue = "0.5"
let doubleValue = Double(stringValue)

这看起来很简单,但有一个问题:doubleValue的类型最终是Double?而不是Double——是的,这是一个可选的。你看,Swift不能确定字符串是否包含可以安全地转换为Double的内容,所以它使用可选值:如果转换成功,那么我们的optional将包含结果值,但是如果字符串是无效的(“Fish”,莎士比亚的全集,etc)则可选项将设置为nil

这里有几种处理可选性的方法,但最简单的方法是使用空合运算符??,以确保始终存在有效值。

代码语言:javascript复制
let orderAmount = Double(checkAmount) ?? 0

它将尝试将checkAmount转换为Double,但如果由于某种原因失败,则将使用0。

现在我们有了三个输入值,是时候做我们的数学题了。这还需要三个步骤:

1、我们可以通过将orderAmount除以100并乘以tipSelection来计算tip值。 2、我们可以通过向orderAmount添加tip值来计算账单的总金额。 3、我们可以用总金额除以人数来计算出每人的金额。

一旦完成,我们可以返回每人的金额,我们就完成了。

将属性中的return 0替换为:

代码语言:javascript复制
let tipValue = orderAmount / 100 * tipSelection
let grandTotal = orderAmount   tipValue
let amountPerPerson = grandTotal / peopleCount

return amountPerPerson

如果您正确地执行了所有操作,那么您的代码应该如下所示:

代码语言:javascript复制
var totalPerPerson: Double {
    let peopleCount = Double(numberOfPeople   2)
    let tipSelection = Double(tipPercentages[tipPercentage])
    let orderAmount = Double(checkAmount) ?? 0

    let tipValue = orderAmount / 100 * tipSelection
    let grandTotal = orderAmount   tipValue
    let amountPerPerson = grandTotal / peopleCount

    return amountPerPerson
}

既然totalPerPerson给出了正确的值,我们可以更改表中的最后一部分,以便它显示正确的文本。

将这段代码:

代码语言:javascript复制
Section {
    Text("$(checkAmount)")
}

替换为:

代码语言:javascript复制
Section {
    Text("$(totalPerPerson)")
}

现在试着运行应用程序,看看你怎么想。您应该会发现,因为构成总数的所有值都用@State标记,更改其中任何一个值都会导致总数自动重新计算。

希望您现在可以亲眼看到,SwiftUI的视图是其状态的函数——当状态改变时,视图会自动更新以匹配。

在我们完成之前,我们要解决显示的一个小问题,这就是总价格的显示方式。我们的金额计算使用了双精度,这意味着Swift给我们的精度比我们需要的要高得多——我们预计会看到25.50美元,但实际上是25.500000美元。

我们可以通过使用SwiftUI添加的一个简洁的字符串插值功能来解决这个问题:决定数字应该如何在字符串中格式化的能力。这实际上可以追溯到C编程语言,所以语法一开始有点奇怪:我们编写一个名为specifier的字符串,给它值“%.2f”。这是C的语法,意思是“两位浮点数”

非常粗略地说,“%f”意味着“任何类型的浮点数”,在我们的例子中,它将是整个数字。另一个选择是“%g”,它也做同样的事情,只是它从末尾去掉了不重要的零——12.50美元将被写成12.5美元。把“.2”放进混合物中,就是要求小数点后有两位数字,不管它们是什么。Swift足够聪明地绕过它们,所以我们仍然可以得到很好的精度。

你可以在Wikipedia上阅读更多关于这些C-style格式说明符的信息:https://en.wikipedia.org/wiki/Printf_format_string——我们不会去其他任何地方,所以如果你想满足你的好奇心,它就在那里!

无论如何,我们希望每人的金额使用新的格式说明符,因此请将总金额文本视图修改为:

代码语言:javascript复制
Text("$(totalPerPerson, specifier: "%.2f")")

现在最后一次运行这个项目——我们完成了!

Calculating the total per person

项目打卡

WeSplit

Previous: 使用分段控件选择百分比

Next: SWeSplit 挑战

0 人点赞