Je suis en train de créer une page pour ajouter des informations sur les joueurs à une base de données locale. J'ai une collection de TextFields pour chaque entrée qui est liée à des éléments dans une structure de joueur.
var body: some View {
VStack {
TextField("First Name", text: $player.FirstName)
.textFieldStyle(RoundedBorderTextFieldStyle())
TextField("Last Name", text: $player.LastName)
.textFieldStyle(RoundedBorderTextFieldStyle())
TextField("Email", text: $player.eMail)
.textFieldStyle(RoundedBorderTextFieldStyle())
TextField("Shirt Number", text: $player.ShirtNumber)
.textFieldStyle(RoundedBorderTextFieldStyle())
TextField("NickName", text: $player.NickName)
.textFieldStyle(RoundedBorderTextFieldStyle())
TextField("Height", text: $player.Height)
.textFieldStyle(RoundedBorderTextFieldStyle())
TextField("Weight", text: $player.Weight)
.textFieldStyle(RoundedBorderTextFieldStyle())
Button(action: {
submitPlayer(player: self.player)T
}) {
Text("Submit")
}
Spacer()
}
}
Ma structure de joueur est
struct Player: Hashable, Codable, Identifiable {
var id: Int
var FirstName: String
var LastName: String
var NickName: String
var eMail: String
var ShirtNumber: Int
var Height: Int
var Weight: Int
}
Le problème est que ShirtNumber, Height et Weight sont tous des valeurs Int. Lorsque je les lie au TextField, j'obtiens une erreur disant Cannot convert value of type 'Binding<Int>' to expected argument type 'Binding<String>'
. Tout ce que j'ai examiné à propos de SwiftUI indique qu'il est impossible d'avoir un TextField avec une valeur Int liée.
Ma question est, serait-il possible de créer une nouvelle classe qui étend TextField mais autorise uniquement les entrées Int et qui lie une variable Int, quelque chose comme ça?
struct IntTextField: TextField {
init(_ text: String, binding: Binding<Int>) {
}
}
Jusqu'à présent, tout ce que j'ai pu trouver est une réponse à une partie de ma question (n'acceptant que l'entrée Int) de this question. Je cherche un moyen de combiner cela avec le Binding<Int>
.
Merci pour l'aide.
Bien sûr, il est possible d'utiliser
TextField("", value: $value, formatter: NumberFormatter())
// .keyboardType(UIKeyboardType.decimalPad) // << uncomment for num pad
et même avec le pavé numérique, mais cela n'empêche pas d'entrer des caractères non numériques dans un tel TextField
, et jusqu'à ce que commit formatter
ne soit pas appelé pour valider l'entrée. Peut-être Apple nous donnera la possibilité de valider la saisie à la volée à l'avenir, mais pas maintenant, ... donc je préfère une manière différente
Voici mon approche pour avoir un champ de texte pour les valeurs numériques (Int, Float, Double, etc.) qui valide la saisie et les limites de type spécifique (par exemple, ne permettez pas d'entrer des valeurs plus longtemps puis rentrez dans la valeur maximale autorisée Int). J'espère que ce serait utile pour quelqu'un aussi. (Bien sûr, des configurations telles que la police, la taille, les couleurs, etc. sont possibles en fonction des besoins d'utilisation)
struct NumberTextField<V>: UIViewRepresentable where V: Numeric & LosslessStringConvertible {
@Binding var value: V
typealias UIViewType = UITextField
func makeUIView(context: UIViewRepresentableContext<NumberTextField>) -> UITextField {
let editField = UITextField()
editField.delegate = context.coordinator
return editField
}
func updateUIView(_ editField: UITextField, context: UIViewRepresentableContext<NumberTextField>) {
editField.text = String(value)
}
func makeCoordinator() -> NumberTextField.Coordinator {
Coordinator(value: $value)
}
class Coordinator: NSObject, UITextFieldDelegate {
var value: Binding<V>
init(value: Binding<V>) {
self.value = value
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
replacementString string: String) -> Bool {
let text = textField.text as NSString?
let newValue = text?.replacingCharacters(in: range, with: string)
if let number = V(newValue ?? "0") {
self.value.wrappedValue = number
return true
} else {
if nil == newValue || newValue!.isEmpty {
self.value.wrappedValue = 0
}
return false
}
}
func textFieldDidEndEditing(_ textField: UITextField, reason: UITextField.DidEndEditingReason) {
if reason == .committed {
textField.resignFirstResponder()
}
}
}
}
struct TestTextFieldWithNumbers: View {
@State private var value = 0
var body: some View {
VStack {
Text("Current value: \(value)")
Divider()
TextField("", value: $value, formatter: NumberFormatter())
// .keyboardType(UIKeyboardType.decimalPad)
Divider()
NumberTextField(value: $value)
.frame(height: 32)
}
}
}
struct TestTextFieldWithNumbers_Previews: PreviewProvider {
static var previews: some View {
TestTextFieldWithNumbers()
}
}