将Binding <Int>与TextField SwiftUI一起使用

时间:2019-12-28 01:33:54

标签: swift xcode swiftui

我目前正在建立一个页面,以将玩家信息添加到本地数据库。对于每个与播放器结构中的元素链接的输入,我都有一个TextFields集合。

APP_URL=http://localhost

我的播放器结构是

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

问题在于ShirtNumber,Height和Weight均为Int值。将它们绑定到TextField时,出现错误消息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 } 。我研究过的关于SwiftUI的一切都说不可能有绑定了Int值的TextField。

我的问题是,是否可以创建一个扩展TextField但仅允许Int输入并绑定一个Int变量的新类?

Cannot convert value of type 'Binding<Int>' to expected argument type 'Binding<String>'

到目前为止,我所能找到的只是对this问题中部分问题的答案(仅接受Int输入)。我正在寻找一种将其与struct IntTextField: TextField { init(_ text: String, binding: Binding<Int>) { } } 结合使用的方法。

感谢您的帮助。

4 个答案:

答案 0 :(得分:5)

只是为了让它更容易观察。

改变这个:

TextField("", text: $intvalue)

那个

TextField("Value", value: $amount, formatter: NumberFormatter())

答案 1 :(得分:2)

实际上,您可以将许多类型与TextField绑定:

      @State var weight: Int = 0
      var body: some View {


       Group{
       Text("\(weight)")
       TextField("Weight", value: $weight, formatter: NumberFormatter())
    }}

答案 2 :(得分:0)

当然可以使用

TextField("", value: $value, formatter: NumberFormatter())
//    .keyboardType(UIKeyboardType.decimalPad) // << uncomment for num pad

甚至使用数字键盘,但这不会阻止在这样的TextField中输入非数字字符,并且直到调用commit 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()
    }
}

答案 3 :(得分:0)

试图让它在没有 UIKit 的情况下工作,因为我正在尝试构建一个小的 macOS 应用程序,所以 UIKit 不存在,所以找到了一个使用两个变量的解决方案(不是最干净但有效)

变量声明:

@State var minutes = 0
@State var minutesString = "0"

TextField 和步进器:

HStack {
    TextField("minutes", text: self.$minutesString)
        .onReceive(Just(self.minutesString)) { newValue in
            let filtered  = newValue.filter { $0.isNumber }
            if filtered != newValue {
                self.minutesString = filtered
                self.minutes = Int(filtered) ?? -1
            }                              
    }
                            
    Stepper("minutes", value: $minutes).onChange(of: self.hours) { newValue in
        self.minutesString = String(newValue)
    }
    .labelsHidden()
}

这将导致在写入 textField 或步进器时更改两个变量,并且不允许输入数字以外的任何内容。

我对整个 swift 事情有点陌生,因此非常感谢任何反馈。