【问题标题】:Use Binding<Int> with a TextField SwiftUI将 Binding<Int> 与 TextField SwiftUI 一起使用
【发布时间】:2020-04-17 19:41:50
【问题描述】:

我目前正在构建一个页面以将玩家信息添加到本地数据库。对于每个输入,我都有一个 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&lt;Int&gt;' to expected argument type 'Binding&lt;String&gt;'。我所研究的关于 SwiftUI 的所有内容都表明,不可能有一个绑定了 Int 值的 TextField。

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

struct IntTextField: TextField {

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

    }
}

到目前为止,我能找到的只是来自this 问题的部分问题的答案(仅接受 Int 输入)。我正在寻找一种将其与Binding&lt;Int&gt; 结合起来的方法。

感谢您的帮助。

【问题讨论】:

    标签: swift xcode swiftui


    【解决方案1】:

    其实你可以用TextField绑定manyTypes:

          @State var weight: Int = 0
          var body: some View {
    
    
           Group{
           Text("\(weight)")
           TextField("Weight", value: $weight, formatter: NumberFormatter())
        }}
    

    【讨论】:

    【解决方案2】:

    当然可以使用

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

    【讨论】:

    • 哇哇哇哇哇哇哇哇哇哇哇!完美的。只缺少一行:editField.keyboardType = .numberPad。如果这是一个数字文本字段,您应该有数字数字键盘。谢谢。
    • 这非常有用。 – 我目前也在尝试使用负整数来完成这项工作。问题(我认为)是value 中不能表示单个“-”。您对如何进行有什么建议吗?
    • 这似乎是更强大的解决方案,尽管“更冗长”。
    • 这不再起作用了:stackoverflow.com/q/65157101
    【解决方案3】:

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

    改变这个:

    TextField("", text: $intvalue)
    

    到那个

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

    【讨论】:

      【解决方案4】:

      我试图在没有 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 的事情有点陌生,因此非常感谢任何反馈。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-12-28
        • 2020-07-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-31
        • 2021-12-24
        • 1970-01-01
        相关资源
        最近更新 更多