Обнаружить Backspace Событие в UITextField
Я ищу решения о том, как захватить событие возврата, большинство ответов Stack Overflow написано на Objective-C, но мне нужно на языке Swift.
Сначала я установил делегат для UITextField и установил его на себя
self.textField.delegate = self;
Тогда я знаю, чтобы использовать shouldChangeCharactersInRange
метод делегата, чтобы определить, был ли нажат backspace, если весь код находится в Objective-C. Мне нужно в Swift использовать следующий метод, как показано ниже.
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
const char * _char = [string cStringUsingEncoding:NSUTF8StringEncoding];
int isBackSpace = strcmp(_char, "\b");
if (isBackSpace == -8) {
// NSLog(@"Backspace was pressed");
}
return YES;
}
13 ответов
Надеюсь поможет тебе:p
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let char = string.cStringUsingEncoding(NSUTF8StringEncoding)!
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
println("Backspace was pressed")
}
return true
}
Я предпочитаю подкласс UITextField
и переопределение deleteBackward()
потому что это гораздо надежнее, чем использование shouldChangeCharactersInRange
:
class MyTextField: UITextField {
override public func deleteBackward() {
if text == "" {
// do something when backspace is tapped/entered in an empty text field
}
// do something for every backspace
super.deleteBackward()
}
}
shouldChangeCharactersInRange
Взлом в сочетании с невидимым символом, помещаемым в текстовое поле, имеет несколько недостатков:
- при подключенной клавиатуре можно поместить курсор перед невидимым символом, и возврат больше не обнаруживается,
- пользователь может даже выбрать этот невидимый символ (используя
Shift Arrow
на клавиатуре или даже, нажав на каретку), и будет смущен этим странным персонажем, - панель автозаполнения предлагает странный выбор, пока есть только этот невидимый персонаж,
placeholder
больше не показывается,- кнопка очистки отображается, даже если она не должна
clearButtonMode = .whileEditing
,
Конечно, переопределение deleteBackward()
это немного неудобно из-за необходимости создания подклассов. Но лучший UX стоит того!
И если подклассы не нужны, например, при использовании UISearchBar
со встроенным UITextField
Метод swizzling тоже должен быть в порядке.
Пожалуйста, не трогайте свой код. Просто поместите это расширение где-нибудь в своем коде. (Swift 4.1)
extension String {
var isBackspace: Bool {
let char = self.cString(using: String.Encoding.utf8)!
return strcmp(char, "\\b") == -92
}
}
А потом просто использовать его в своих функциях
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string.isBackspace {
// do something
}
return true
}
В Свифт 3
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
let char = string.cString(using: String.Encoding.utf8)!
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
print("Backspace was pressed")
}
return true
}
:)
Если вам нужно обнаружить backspace даже в пустом textField (например, если вам нужно автоматически переключиться обратно на prev textField при нажатии backSpace), вы можете использовать комбинацию предложенных методов - добавить невидимый знак и использовать стандартный метод делегата textField:shouldChangeCharactersInRange:replacementString:
как следовать
Создать невидимый знак
private struct Constants { static let InvisibleSign = "\u{200B}" }
Установить делегат для textField
textField.delegate = self
На мероприятии
EditingChanged
проверьте текст и, если необходимо, добавьте невидимый символ, например:@IBAction func didChangeEditingInTextField(sender: UITextField) { if var text = sender.text { if text.characters.count == 1 && text != Constants.InvisibleSign { text = Constants.InvisibleSign.stringByAppendingString(text) sender.text = text } } }
Добавить реализацию метода делегата
textField:shouldChangeCharactersInRange:replacementString:
extension UIViewController : UITextFieldDelegate { // MARK: - UITextFieldDelegate func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { let char = string.cStringUsingEncoding(NSUTF8StringEncoding)! let isBackSpace = strcmp(char, "\\b") if (isBackSpace == -92) { if var string = textField.text { string = string.stringByReplacingOccurrencesOfString(Constants.InvisibleSign, withString: "") if string.characters.count == 1 { //last visible character, if needed u can skip replacement and detect once even in empty text field //for example u can switch to prev textField //do stuff here } } } return true } }
Попробуй это
public func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if(string == "") {
print("Backspace pressed");
return true;
}
}
Примечание. Вы можете вернуть "true", если хотите разрешить возврат. В противном случае вы можете вернуть "ложь".
Я реализовал эту функцию:
И в случае, когда последний textFiled пуст, я просто хочу переключиться на предыдущий textFiled. Я попробовал все ответы выше, но никто не работает нормально в моей ситуации. По какой-то причине, если я добавлю больше логики, чем print
в isBackSpace == -92
в скобках этот метод просто перестал работать...
Как по мне, метод ниже более элегантный и работает как шарм:
стриж
class YourTextField: UITextField {
// MARK: Life cycle
override func awakeFromNib() {
super.awakeFromNib()
}
// MARK: Methods
override func deleteBackward() {
super.deleteBackward()
print("deleteBackward")
}
}
Спасибо @LombaX за ответ
Swift 4
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let char = string.cString(using: String.Encoding.utf8)!
let isBackSpace = strcmp(char, "\\b")
if isBackSpace == -92 {
print("Backspace was pressed")
return false
}
}
Swift 4
Я нахожу сравнение, используя strcmp
не имеет значения. Мы даже не знаем как strcmp
работает за капотом. Во всех других ответах при сравнении текущего символа и \b
результаты -8
в объективе-C и -92
в Свифте. Я написал этот ответ, потому что вышеупомянутые решения не работали для меня. (Версия XCode 9.3 (9E145)
используя Swift 4.1
)
К вашему сведению: каждый символ, который вы вводите, является массивом 1
или более элементов в utf8 Encoding
, символ возврата [0]
, Вы можете попробовать это.
PS: не забудьте назначить правильное delegates
на ваш textFields
,
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
let char = string.cString(using: String.Encoding.utf8)!
if (char.elementsEqual([0])) {
print("Backspace was pressed")
}
else {
print("WHAT DOES THE FOX SAY ?\n")
print(char)
}
return true
}
Swift 4
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
//MARK:- If Delete button click
let char = string.cString(using: String.Encoding.utf8)!
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
print("Backspace was pressed")
return true
}
}
Swift 5: согласно документации делегата текстового представления , если текст замены, возвращаемый методом shouldChangeTextIn, пуст, пользователь нажал кнопку возврата. Если верхняя граница диапазона больше, чем нижняя граница диапазона (или количество диапазонов равно 1 или больше), текст следует удалить. Если верхняя и нижняя границы диапазона совпадают (или обе равны 0), тогда нет текста для удаления (диапазон длины 0 не должен быть заменен ничем). Я тестировал, и это будет вызываться даже в пустом текстовом поле.
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
guard text.isEmpty else { return true } // No backspace pressed
if (range.upperBound > range.lowerBound) {
print("Backspace pressed")
} else if (range.upperBound == range.lowerBound) {
print("Backspace pressed but no text to delete")
if (textView.text.isEmpty) || (textView.text == nil) {
print("Text view is empty")
}
}
return true
}
Swift 4: если пользователь нажимает кнопку возврата, строка становится пустой, поэтому этот подход заставляет textField принимать символы только из указанного набора символов (в данном случае utf8 символов) и символы возврата (в случае string.isEmpty).
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string.cString(using: String.Encoding.utf8) != nil {
return true
} else if string.isEmpty {
return true
} else {
return false
}
}
Я пришел сюда в поисках ответа о том, как обнаружить удаления. Я хотел знать, когда UITextView был пуст после того, как пользователь коснулсяdelete
. Во время тестирования я понял, что мне нужно также фиксировать удаление и вырезание целых слов. Вот ответ, который я придумал.
extension SomeViewController: UITextViewDelegate {
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let deleteTapped = text == ""
let cursorAtBeginning = range.location == 0
let deletedCharactersEqualToTextViewCount = range.length == textView.text.count
let everythingWasDeleted = deleteTapped && cursorAtBeginning && deletedCharactersEqualToTextViewCount
if everythingWasDeleted {
// Handle newly empty view from deletion
} else {
// Handle other situation
}
return true
}
}
Спасибо за все предыдущие полезные ответы. Я надеюсь, что это помогает кому-то.