简体   繁体   English

使用绑定<Int>使用 TextField SwiftUI

[英]Use Binding<Int> with a TextField SwiftUI

I am currently building a page to add player information to a local database.我目前正在构建一个页面以将玩家信息添加到本地数据库。 I have a collection of TextFields for each input which is linked to elements in a player struct.我为每个链接到播放器结构中的元素的输入都有一个 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()
        }
    }

My player struct is我的播放器结构是

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
}

The issue is that ShirtNumber, Height, and Weight are all Int values.问题是 ShirtNumber、Height 和 Weight 都是 Int 值。 When I bind them to the TextField I get an error saying Cannot convert value of type 'Binding<Int>' to expected argument type 'Binding<String>' .当我将它们绑定到 TextField 时,我收到一条错误消息,提示Cannot convert value of type 'Binding<Int>' to expected argument type 'Binding<String>' Everything I have looked into about SwiftUI says it's impossible to have a TextField with an Int value bound to it.我所研究的关于 SwiftUI 的所有内容都表明,不可能有一个绑定了 Int 值的 TextField。

My question is, would it be possible to create a new class that extends TextField but allows for only Int inputs and that binds an Int variable, something like this?我的问题是,是否可以创建一个新类来扩展 TextField 但只允许 Int 输入并绑定一个 Int 变量,像这样?

struct IntTextField: TextField {

    init(_ text: String, binding: Binding<Int>) {

    }
}

So far all I have been able to find is an answer to part of my question (accepting only Int input) from this question.到目前为止,所有我已经能够找到的是从回答我的问题的一部分(只接受INT输入) 这个问题。 I am looking for a way to combine this with the Binding<Int> .我正在寻找一种方法将它与Binding<Int>结合起来。

Thanks for the help.谢谢您的帮助。

Actually , you can binding manyTypes with TextField :实际上,您可以使用TextField绑定 manyTypes :

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


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

Of course it is possible to use当然也可以使用

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

and even with Numeric Pad, but this does not prevent to enter non-numeric characters into such TextField , and until commit formatter is not called to validate input.甚至使用数字键盘,但这并不能阻止将非数字字符输入到此类TextField ,直到未调用提交formatter来验证输入。 Maybe Apple will give us possibility to validate input on the fly in future, but not now, ... so I prefer different way也许 Apple 会给我们在未来即时验证输入的可能性,但不是现在,......所以我更喜欢不同的方式

Here is my approach to have text field for numeric values (Int, Float, Double, etc.) which validates input and limits of specific type (say do not allow to enter values longer then fit into Int maximum allowed value).这是我为数值(Int、Float、Double 等)设置文本字段的方法,它验证特定类型的输入和限制(比如不允许输入的值超过 Int 的最大允许值)。 Hope it would be helpful for someone as well.希望它对某人也有帮助。 (Of course configurations like font, size, colors, etc. are possible per usage needs) (当然可以根据使用需要进行字体、大小、颜色等配置)

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

Just to make it more observable.只是为了让它更容易观察。

change this:改变这个:

TextField("", text: $intvalue)

to that到那个

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

Was trying to make it work without UIKit since I am trying to build a small macOS app and so UIKit is not present there so found a solution which uses two variables (not the cleanest but works)试图让它在没有 UIKit 的情况下工作,因为我正在尝试构建一个小的 macOS 应用程序,所以 UIKit 不存在,所以找到了一个使用两个变量的解决方案(不是最干净但有效)

Variable declaration:变量声明:

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

TextField and Stepper:文本字段和步进器:

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

Which would result in both variables being changed when either the textField or the stepper is being written to, and does not allow the input of anything other than numbers.这将导致在写入 textField 或步进器时更改两个变量,并且不允许输入数字以外的任何内容。

I am kinda new to the whole swift thing and so any feedback is greatly appreciated.我对整个快速的事情有点陌生,因此非常感谢任何反馈。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM