我正在为 swift 3 中的更完整示例添加此答案。
基本上,我需要一个 pincode 类型的视图,其中有多个文本字段,每个单元格中允许一个字符。
像这样
我首先创建了 UITextField 的子类和定义新函数的协议。
protocol MYDeleteActionTextFieldDelegate {
func textFieldDidSelectDeleteButton(_ textField: UITextField) -> Void
}
class MYDeleteActionTextField: UITextField {
var deleteDelegate: MYDeleteActionTextFieldDelegate?
override func deleteBackward() {
// Need to call this before super or the textfield edit may already be in place
self.deleteDelegate?.textFieldDidSelectDeleteButton(self)
super.deleteBackward()
}
}
然后您使用新的子类创建文本字段并在您的视图控制器中实现委托。就我而言,我在数组中管理文本字段以方便使用,并使用 PureLayout 布局单元格。我这样存储它们
var pinFields = UITextField
然后在viewDidLoad() 中,我将所有引脚字段添加到数组中,如下所示:
for _ in 1...6 {
let field = EDFDeleteActionTextField.init(forAutoLayout: ())
field.addTarget(self, action: #selector(textFieldDidChange(textField:)), for: UIControlEvents.editingChanged)
field.delegate = self
field.deleteDelegate = self
field.textAlignment = .center
field.font = UIFont.newBigTitle()
field.textColor = UIColor.edfBlue()
field.backgroundColor = UIColor.edfWhite()
self.pinFields.append(field)
self.pinView.addSubview(field)
}
现在您只需要响应所有适当的委托方法和上面添加的textFieldDidChange 目标。
// MARK: UITextFieldDelegate
func textFieldDidChange(textField: UITextField) {
// If the user typed one character, move to the next cell.
if (textField.text?.characters.count == 1) {
let index = pinFields.index(of: textField)
textField.resignFirstResponder()
if (pinFields.count > index! + 1) {
pinFields[index! + 1].becomeFirstResponder()
}
} // If they deleted the character move to previous cell
else if (textField.text?.characters.count == 0) {
let index = pinFields.index(of: textField)
if (index! - 1 >= 0) {
pinFields[index! - 1].becomeFirstResponder()
}
}
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if range.location > 0 {
let index = pinFields.index(of: textField)
// If there is already text in the text field and the next cell is empty - move the newly typed character to that cell.
if (pinFields.count > index! + 1) {
let nextField = pinFields[index! + 1]
if (nextField.text?.characters.count == 0) {
textField.resignFirstResponder()
nextField.becomeFirstResponder()
nextField.text = string
}
}
return false
}
return true
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return false
}
// MARK: EDFDeleteActionTextFieldDelegate
func textFieldDidSelectDeleteButton(_ textField: UITextField) {
// If user clicked delete, and there are no characters, move to previous cell if available.
// If there are characters, it is handled in UITextFieldDelegate
if (textField.text?.characters.count == 0) {
let index = pinFields.index(of: textField)
if (index! - 1 >= 0) {
pinFields[index! - 1].becomeFirstResponder()
}
else {
textField.resignFirstResponder()
}
}
}
我将省略无聊的部分(例如布局文本字段等),因为这个通用功能在更多情况下比这个 pincode 视图有用,但是实现这个子类和协议应该提供你需要的所有功能对于类似类型的视图并解决手头的问题(这可能需要类似的东西)。
编码愉快。