所以我正在尝试学习SwiftUI和Combine。我通常通过制作一个简单的小费计算器来开始新技术。
我似乎得到了一个随机的“通话中的额外参数”。编码时出错 这是我的SwiftUI文件
import SwiftUI
internal enum ReceiptRowType {
case subtotal
case tax
case total
case tip
case grandTotal
}
struct TipView: View {
@ObservedObject internal var adBannerView: BannerAdView = BannerAdView()
@ObservedObject internal var receiptViewModel: ReceiptViewModel
private let percentageFormatter: NumberFormatter = {
let f = NumberFormatter()
f.numberStyle = .percent
return f
}()
var body: some View {
ZStack {
Color.white
.scaledToFit()
VStack {
if adBannerView.adHasLoaded {
adBannerView
.frame(maxHeight: adBannerView.adHeight)
.animation(.easeInOut(duration: 2.0))
}
BorderView()
Text(ARCHLocalizedStrings.receipt)
.foregroundColor(Color.gray)
BorderView()
HStack {
Spacer()
Button(action: {
self.receiptViewModel.addNewReceiptItem()
}) {
Text(ARCHLocalizedStrings.buttonTitleAddItem)
}
}
BorderView()
ScrollView {
ForEach(receiptViewModel.receiptItems) { receiptItem in
ItemView(receiptItem: receiptItem)
if receiptItem != self.receiptViewModel.receiptItems.last {
Divider()
}
}
}
BorderView()
BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.subtotal,
title: ARCHLocalizedStrings.subtotal)
BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.tax,
title: ARCHLocalizedStrings.tax)
}
.padding(.horizontal, ARCHSwiftUILayoutConstants.defaultPaddingAndSpacing)
}
}
}
struct BorderView: View {
var body: some View {
Text("================================")
.lineLimit(1)
.foregroundColor(Color.gray)
.minimumScaleFactor(0.5)
}
}
struct ItemView: View {
@ObservedObject var receiptItem: ReceiptItemViewModel
var body: some View {
HStack {
TextField(receiptItem.name, text: $receiptItem.name)
.textFieldStyle(RoundedBorderTextFieldStyle())
.foregroundColor(Color.gray)
.multilineTextAlignment(TextAlignment.leading)
TextField("Price", value: $receiptItem.price, formatter: ARCHUtilities.currencyFormatter)
.textFieldStyle(RoundedBorderTextFieldStyle())
.foregroundColor(Color.gray)
.multilineTextAlignment(TextAlignment.trailing)
.minimumScaleFactor(0.5)
.frame(width: ARCHSwiftUILayoutConstants.widthForCurrency)
}
}
}
struct BottomOfReceiptRow: View {
@ObservedObject internal var receiptViewModel: ReceiptViewModel
internal var type: ReceiptRowType
internal var title: String
var body: some View {
HStack {
Spacer()
Text(title)
.foregroundColor(Color.gray)
if type == ReceiptRowType.subtotal {
Text("\(receiptViewModel.subtotal)")
.foregroundColor(Color.gray)
.frame(width: ARCHSwiftUILayoutConstants.widthForCurrency)
} else if type == ReceiptRowType.tax {
Text("\(receiptViewModel.taxRate)")
.foregroundColor(Color.gray)
.frame(width: ARCHSwiftUILayoutConstants.widthForCurrency)
} else if type == ReceiptRowType.total {
Text("\(receiptViewModel.total)")
.foregroundColor(Color.gray)
.frame(width: ARCHSwiftUILayoutConstants.widthForCurrency)
} else if type == ReceiptRowType.tip {
} else if type == ReceiptRowType.grandTotal {
Text("\(receiptViewModel.grandTotal)")
.foregroundColor(Color.gray)
.frame(width: ARCHSwiftUILayoutConstants.widthForCurrency)
}
}
}
}
struct TipView_Previews: PreviewProvider {
static var previews: some View {
TipView(receiptViewModel: ReceiptViewModel())
}
}
但是,如果我在TipView主体上添加另一个视图(任何视图),我似乎会收到“调用中的额外参数”错误。
有人知道发生了什么吗?
答案 0 :(得分:60)
尝试围绕您的视图创建一个群组{}。 Swiftui只允许10个...与组一起可以添加更多。或使用子视图...(也将是更简洁的代码)
答案 1 :(得分:8)
SwiftUI中的@ViewBuilder系统在任何给定的视图容器中限制为10个视图。没有第11个视图的参数,因此您会收到该错误。
这里的问题是您的VStack处于最大容量,但是您可以将这些现有视图包装在其他容器中。作为一个非常基本的示例,它将允许您显示10个BottomReceiptRow
视图:
var body: some View {
ZStack {
Color.white
.scaledToFit()
// Modifications start here
VStack {
if adBannerView.adHasLoaded {
adBannerView
.frame(maxHeight: adBannerView.adHeight)
.animation(.easeInOut(duration: 2.0))
}
BorderView()
Text(ARCHLocalizedStrings.receipt)
.foregroundColor(Color.gray)
BorderView()
HStack {
Spacer()
Button(action: {
self.receiptViewModel.addNewReceiptItem()
}) {
Text(ARCHLocalizedStrings.buttonTitleAddItem)
}
}
BorderView()
ScrollView {
ForEach(receiptViewModel.receiptItems) { receiptItem in
ItemView(receiptItem: receiptItem)
if receiptItem != self.receiptViewModel.receiptItems.last {
Divider()
}
}
}
BorderView()
Group {
BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.subtotal,
title: ARCHLocalizedStrings.subtotal)
BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.tax,
title: ARCHLocalizedStrings.tax)
BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue,
title: ARCHLocalizedStrings.someValue)
BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue2,
title: ARCHLocalizedStrings.someValue2)
BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue3,
title: ARCHLocalizedStrings.someValue3)
BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue4,
title: ARCHLocalizedStrings.someValue4)
BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue5,
title: ARCHLocalizedStrings.someValue5)
}
// Modifications end here
}
.padding(.horizontal, ARCHSwiftUILayoutConstants.defaultPaddingAndSpacing)
}
}
您可能希望将这些部分完全重构为它们自己的View
,因为组合使代码更易于阅读。不过,这里并非严格必要。
如果您确实想这样做,可以考虑一个示例,其中那些收据行都在各自的视图中,例如:
var body: some View {
ZStack {
Color.white
.scaledToFit()
VStack {
if adBannerView.adHasLoaded {
adBannerView
.frame(maxHeight: adBannerView.adHeight)
.animation(.easeInOut(duration: 2.0))
}
BorderView()
Text(ARCHLocalizedStrings.receipt)
.foregroundColor(Color.gray)
BorderView()
HStack {
Spacer()
Button(action: {
self.receiptViewModel.addNewReceiptItem()
}) {
Text(ARCHLocalizedStrings.buttonTitleAddItem)
}
}
BorderView()
ScrollView {
ForEach(receiptViewModel.receiptItems) { receiptItem in
ItemView(receiptItem: receiptItem)
if receiptItem != self.receiptViewModel.receiptItems.last {
Divider()
}
}
}
BorderView()
bottomRow
}
.padding(.horizontal, ARCHSwiftUILayoutConstants.defaultPaddingAndSpacing)
}
}
// Additional computed property in TipView
var bottomRow: some View {
Group {
BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.subtotal,
title: ARCHLocalizedStrings.subtotal)
BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.tax,
title: ARCHLocalizedStrings.tax)
BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue,
title: ARCHLocalizedStrings.someValue)
BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue2,
title: ARCHLocalizedStrings.someValue2)
BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue3,
title: ARCHLocalizedStrings.someValue3)
BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue4,
title: ARCHLocalizedStrings.someValue4)
BottomOfReceiptRow(receiptViewModel: receiptViewModel,
type: ReceiptRowType.someValue5,
title: ARCHLocalizedStrings.someValue5)
}
} // end bottomRow