web-dev-qa-db-ja.com

TextField SwiftUIでBinding <Int>を使用する

現在、ローカルデータベースにプレーヤー情報を追加するページを作成しています。プレーヤーの構造体の要素にリンクされている各入力の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>と組み合わせる方法を探しています。

助けてくれてありがとう。

2
Bernard

もちろん使用可能です

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()
    }
}
1
Asperi