我们将首先创建一个保存单笔交易数据的结构。
一笔交易是由 amount
,以 price
和一个 value
。所有交易都存储在 TradesModel
,这将进行 DCA(美元成本平均)所需的所有计算。
didSet
使用属性观察器,以便 trades
当用户想要增加显示的交易数量时,数组会被赋予一个新的空交易。
这使数组的大小与我们期望在屏幕上看到的数字保持一致,从而消除了索引超出范围错误的可能性。
该界面将采用包含三列的表格形式:金额、价格和价值。这些与交易的属性适当一致,每个属性都将使用自定义设置 TextField
这将被称为 NumberTextField
.
在开始之前,我们需要创建一个简单的标题行,为每个列提供一个标题。如果我们不明确指出哪个是哪个,就没有其他方法可以区分金额与价格或价值。
你可能会注意到上面的整个 HStack 有 disabled
修饰符设置为 true
。这给出了每个 TextField
与应用程序中其他内容的外观相同,但用户无法将这些标题编辑为他们想要的任何内容。
NumberTextField
弥合了之间的差距 TextField
,它使用一个 String
用于输入,和一个 Double
,这是我们希望数据采用的格式。
TextField
有十进制键盘,因此传统的字母数字键盘将不会显示。这极大地减少了可能的字符数量,但仍然没有什么可以阻止用户输入多个点。这不会成功转换为 Double
,所以我们不希望这种情况成为可能。
的延伸 String
提供了一个计算属性,可以让您轻松检查是否有多个点,并将其存储在 valid
属性。
当输入无效时, TextField
会将输入显示为红色,并且不会尝试将值转换为 Double
。如果有效,该值将被设置并发送回 Binding
.
TotalRowView
计算所有交易金额的总和,以便您可以看到您拥有的金额。此处还计算并显示了总成本。它们之间是平均美元成本,其计算方法是用总价值除以总金额。这些值中的每一个都显示为常量字符串 TextField
无法编辑,因此它们与应用程序的其余部分具有相同的样式。
TradeQuantityView
允许您控制有多少行。由于每一行代表一笔交易,因此您需要在进行交易时添加新交易。这一行只是一个 Stepper
显示交易数量。
不幸的是 Stepper
需要一个封闭的可能值范围,因此必须对最大交易数量进行硬编码。该最大数字可以是您想要的任何值,但无法指定没有最大值的范围。
在某些方面,这是最重要的视图,因为它允许您输入要进行的美元成本平均计算的数据。当金额或价格 TextField
被编辑, onChange
闭包调用 setValue
功能。
这会再次计算该值,这只是其他两个数字的乘法。然后,交易会在 trades 数组中更新,该数组作为 @Binding
财产。进行检查以确保数组中存在预期的索引,从而防止索引超出范围错误。
然而,由于更新数组中不存在的交易是一种意外行为,我仍然添加了 fatalError
这解释了为什么这是一个失败状态。
主应用程序只是迄今为止在 SwiftUI 中创建的所有行的组合 Form
。这使它的外观非常类似于 iOS 的“设置”应用程序,并且当屏幕上的行数过多时,它会自动填充任何设备的屏幕并滚动。
视图只传递他们需要的内容,例如交易总数 TradeQuantityView
以及总金额和价值 TotalRowView
.
A ForEach
用于显示每个数字的一笔交易,最多可达所选交易的总数 TradeQuantityView
,并传入索引,以便在发生更改时可以更新数组。
它应该是这样的: