現在、ローカルデータベースにプレーヤー情報を追加するページを作成しています。プレーヤーの構造体の要素にリンクされている各入力のTextFieldのコレクションがあります。
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()
}
}
私のプレーヤーの構造は
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
}
問題は、ShirtNumber、Height、およびWeightがすべてInt値であることです。それらをTextFieldにバインドすると、Cannot convert value of type 'Binding<Int>' to expected argument type 'Binding<String>'
というエラーが表示されます。 SwiftUIについて私が調べたすべてのことは、それにバインドされたInt値を持つTextFieldを持つことは不可能であると述べています。
私の質問は、TextFieldを拡張し、Int入力のみを許可し、Int変数をバインドする新しいクラスを作成することは可能でしょうか?
struct IntTextField: TextField {
init(_ text: String, binding: Binding<Int>) {
}
}
これまでのところ、私が見つけることができたのは this 質問からの私の質問の一部(Int入力のみを受け入れる)への回答です。これをBinding<Int>
と組み合わせる方法を探しています。
助けてくれてありがとう。
もちろん使用可能です
TextField("", value: $value, formatter: NumberFormatter())
// .keyboardType(UIKeyboardType.decimalPad) // << uncomment for num pad
数値パッドを使用する場合でも、数字以外の文字をそのようなTextField
に入力することは妨げられません。入力を検証するためにformatter
が呼び出されるまで呼び出されません。たぶんAppleは将来的にオンザフライで入力を検証する可能性を提供しますが、今はそうではありません...それで私は別の方法を好みます
これは、特定のタイプの入力と制限を検証する数値(Int、Float、Doubleなど)のテキストフィールドを使用するための私のアプローチです(たとえば、値を入力してから、Intの最大許容値に収まらないようにします)。それが誰かにも役立つことを願っています。 (もちろん、フォント、サイズ、色などの設定は、使用ニーズごとに可能です)
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()
}
}