J'essaye donc d'apprendre SwiftUI et Combine. Je commence généralement une nouvelle technologie en créant un simple calculateur de pourboire.
Il semble que je reçois un "argument supplémentaire lors de l'appel" au hasard. erreur lors du codage Voici mon fichier 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())
}
}
Cependant, si j'ajoute une autre vue sur le corps de TipView (toute vue), il me semble obtenir une erreur "Argument supplémentaire dans l'appel".
Quelqu'un sait-il ce qui se passe?
Le système @ViewBuilder dans SwiftUI est limité à 10 vues dans un conteneur de vues donné. Il n'y a aucun argument pour une 11e vue, donc vous obtenez cette erreur.
Le problème ici est que votre VStack est à sa capacité maximale, mais vous pouvez envelopper ces vues existantes à l'intérieur d'autres conteneurs. Comme exemple très basique qui vous permettrait d'afficher 10 vues 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)
}
}
Vous préférerez peut-être refactoriser complètement ces sections dans leur propre View
car la composition rend le code plus facile à lire. Ce n'est cependant pas strictement nécessaire ici.
Si vous voulez faire cela, vous pouvez envisager un exemple où ces lignes de reçu sont toutes dans leur propre vue, comme:
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