我已经创建了UITextField的子类,我想拦截用户输入的任何字符并执行一些验证。查看文档时,UITextField符合UIKeyInput
,并且当用户在键盘上键入字符(documentation)时应调用insertText()
方法。
这是一个非常基本的例子:
import UIKit
class CustomTextField: UITextField {
override func insertText(_ text: String) {
print("Character Typed: \(text)") // never executes
super.insertText(text)
}
override func deleteBackward() {
print("deleting character") // executes
super.deleteBackward()
}
}
根据评论,永远不会调用insertText
。相反,deleteBackward()
(也来自UIKeyInput)会按预期调用。
我创建子类的原因是控件将在整个应用程序中重复使用。如果有一种方法可以将它封装在控件中,那么让具有该字段实例的每个ViewController重新实现验证逻辑真的没有意义。
虽然我可以通过让我的子类符合UITextFieldDelegate
来解决问题,然后设置delegate = self
,然后我就失去了任何其他对象成为委托的能力该领域,创造了一个新问题。
在UITextField的子类中拦截键盘中字符的最佳方法是什么?
似乎覆盖insertText()
无法正常工作,是否还有另一种方法来监控文字更改事件?
答案 0 :(得分:1)
尝试使用此方法。将以下内容添加到CustomTextField类。它是EMAIL字段的处理程序 - 不允许两次输入“@”等等:
class CustomTextField: UITextField {
override func awakeFromNib() {
self.addTarget(self, action: #selector(self.textDidchange), for: .editingChanged)
self.delegate = self
}
func textDidchange() {
// print(self.text)
}
}
extension CustomTextField: UITextFieldDelegate {
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
return handleEmailField(withRange: range, withReplacementString: string)
}
func handleEmailField(withRange range: NSRange, withReplacementString replacementString: String) -> Bool {
var illegalCharactersSet = CharacterSet.init(charactersIn: "?><,\\/|`~\'\"[]{}±#$%^&*()=+")
let currentString = self.text! as NSString
let newString = currentString.replacingCharacters(in: range, with: replacementString)
if currentString.length == 0 && replacementString == "@" {
return false
}
if currentString.contains("@") {
illegalCharactersSet = CharacterSet.init(charactersIn: "?><,\\/|`~\'\"[]{}±#$%^&*()=+@")
}
let components = replacementString.components(separatedBy: illegalCharactersSet)
if components.count > 1 {
return false
}
return newString.characters.count <= 40
}
}
答案 1 :(得分:0)
对于你所要求的内容而言,这可能会有点过头了但是我知道在没有使用委托方法的情况下做这样的事情的最好方法是使用Reactive Functional Programming,这样就可以了使用Observable对象监听UITextField的事件。我有一些使用ReactiveKit更具体Bond的经验,因此您只需要一两行代码来实现您的需求。
答案 2 :(得分:0)
这是我最后为遇到同样问题的人所做的事情。
这里的代码包含一个简单的验证示例:
import UIKit
class CustomTextField: UITextField {
// Keep a copy of the last valid state so we can revert a change if it fails validation
private var lastValidText: String?
// Subscribe to 'editing changed' notofications from self
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.addTarget(self, action: #selector(textDidChange), for: .editingChanged)
}
override init(frame: CGRect) {
super.init(frame: frame)
self.addTarget(self, action: #selector(textDidChange), for: .editingChanged)
}
func textDidChange() {
let validationRegex = "^(a|e|i|o|u)+$"
if let currentText = self.text, currentText != "" {
if currentText.range(of: validationRegex, options: .regularExpression) != nil {
// The update is valid - update the last valid state
lastValidText = currentText
} else {
// The udate failed validation - revert
self.text = lastValidText
}
} else {
// The field is empty. This is a valid state so reset last valid state to nil
self.text = nil
lastValidText = nil
}
}
}