swift - SwiftUI 和 Combine - 如何创建一个具有与用户选择对应的字段数的表单
问题描述
我正在创建一个基本的 Rent Splitting 应用程序来了解 Swift UI 和 Combine。我想要一个主屏幕,用户首先选择他们共享的室友数量,然后根据该选择,向他们显示一个表单,其中包含与该数字对应的字段。到目前为止,我有 HomeView:
import SwiftUI
import Combine
struct HomeScreenView: View {
@ObservedObject private var viewModel: HomeScreenViewModel
init(viewModel: HomeScreenViewModel){
self.viewModel = viewModel
}
var body: some View {
NavigationView {
VStack {
Text("Welcome to Fair Rent!")
Text("Please select how many housemates you live with:")
.lineLimit(nil)
.padding(5.0)
NavigationLink(destination: FairRentView(viewModel: FairRentViewModel(Amounts())))
{
Text("1")
}
NavigationLink(destination: FairRentView(viewModel: FairRentViewModel(Amounts())))
{
Text("2")
}
NavigationLink(destination: FairRentView(viewModel: FairRentViewModel(Amounts())))
{
Text("3")
}
NavigationLink(destination: FairRentView(viewModel: FairRentViewModel(Amounts())))
{
Text("4")
}
NavigationLink(destination: FairRentView(viewModel: FairRentViewModel(Amounts())))
{
Text("5")
}
NavigationLink(destination: FairRentView(viewModel: FairRentViewModel(Amounts())))
{
Text("6")
}
NavigationLink(destination: FairRentView(viewModel: FairRentViewModel(Amounts())))
{
Text("7")
}
}
}
}
}
struct HomeScreenView_Previews: PreviewProvider {
static var previews: some View {
HomeScreenView(viewModel: HomeScreenViewModel(Variables()))
}
}
根据他们点击的数字,他们将被带到 FairRentView:
import SwiftUI
import Combine
struct FairRentView: View {
@ObservedObject private var viewModel: FairRentViewModel
init(viewModel: FairRentViewModel){
self.viewModel = viewModel
}
var body: some View {
NavigationView {
Form {
Section(header: Text("Enter the total monthly rent:")) {
TextField("Total rent", text: $viewModel.amount.totalRent)
.keyboardType(.decimalPad)
}
Section(header: Text("Enter your monthly income:")) {
TextField("Your monthly wage", text: $viewModel.amount.myMonthlyIncome)
.keyboardType(.decimalPad)
}
Section(header: Text("Enter your housemate's monthly income:")) {
TextField("Housemate's monthly income", text: $viewModel.amount.housemateMonthlyIncome)
.keyboardType(.decimalPad)
}
Section {
Text("Your share: £\(viewModel.yourShare, specifier: "%.2f")")
}
}
.navigationBarTitle("FairRent")
}
}
}
struct FairRentView_Previews: PreviewProvider {
static var previews: some View {
FairRentView(viewModel: FairRentViewModel(Amounts()))
}
}
我希望租金是基于工资的。目前,您可以看到只有一个表单字段可以输入室友的工资,而不考虑是否有多个室友。我希望这些字段的数量与用户在 HomeScreen 上选择的数量相对应。我对 SwiftUI 很陌生,不确定最好的方法。谁能指出我正确的方向?我正在尽力使用组合并确认 MVVM 模式。
谢谢
解决方案
由于 SwiftUI 是数据驱动的,其中视图是基于数据生成的,因此您需要一个地方来将每个室友的金额存储在某个地方,比如在视图模型中的一个数组中。然后,您将遍历数组以生成TextField
s.
这是一个概念性示例:
class FairRentViewModel: ObservableObject {
@Published var incomes: [String]
init(for housemates: Int) {
self.incomes = Array(repeating: "", count: housemates)
}
}
(我使用 aString
作为简化,所以以后更容易绑定到 a TextField
)
然后视图将遍历数组:
struct FairRentView: View {
@ObservedObject var vm: FairRentViewModel
var body: some View {
ForEach(vm.incomes.indices, id: \.self) { idx in
TextField("Housemate \(idx + 1)", text: self.$vm.incomes[idx])
}
}
}
然后在父视图中,您可以FairRentView
使用正确数量的家庭进行实例化。同样,这是一种简化,因为您可能也希望在这里有一个循环。
struct HomeScreenView: View {
var body: some View {
NavigationView {
VStack {
NavigationLink(destination: FairRentView(vm: FairRentViewModel(for: 2)) {
Text(2)
}
NavigationLink(destination: FairRentView(vm: FairRentViewModel(for: 3)) {
Text(3)
}
// .. etc
}
}
}
}
推荐阅读
- typescript - 你如何在同一个事件发射器中处理多种类型-Typescript
- vba - VBA - 根据标题复制粘贴值
- android - google_play_services_version 没有正确的值
- stripe-payments - Stripe Connect API - 如何检索已连接帐户的状态?
- javascript - 将带有双引号的字符串字段从烧瓶传递到javascript
- portaudio - sounddevice.PortAudioError:打开 OutputStream 时出错:内部 PortAudio 错误 [PaErrorCode -9986]
- python - fastapi - 可选的 OAuth2 身份验证
- vue.js - v-on 处理程序中的错误(Promise/async):“TypeError:无法读取未定义的属性‘个人’”
- qt - 在单击时显示捕获的图像
- javascript - 如何在调用渲染方法之前从 API 获取数据?(反应,护照,快递)