Я добавляю этот ответ для более полного примера в swift 3. По сути, мне нужно представление типа пин-кода, где у меня есть несколько текстовых полей, которые позволяют один символ в каждой ячейке.
вот так
Я начал с создания подкласса 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()
}
}
}
Я опущу скучные части (такие как размещение текстовых полей и т. д.), так как это общеефункциональность полезна в большем числе случаев, чем это представление с пин-кодом, но реализация этого дочернего класса и протокола должна предоставить все функциональные возможности, которые вам понадобятся для аналогичных представлений типов, и решить для рассматриваемого вопроса (который, вероятно, нуждается в чем-то подобном).
Счастливого кодирования.