I am searching for solutions on how to capture a backspace event, most Stack Overflow answers are in Objective-C but I need on Swift language.
First I have set delegate for the UITextField and set it to self
self.textField.delegate = self;
Then I know to use shouldChangeCharactersInRange
delegate method to detect if a backspace was pressed is all code are in Objective-C. I need in Swift these following method as below is used.
-(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;
}
Swift 4.2
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if let char = string.cString(using: String.Encoding.utf8) {
let isBackSpace = strcmp(char, "\\b")
if (isBackSpace == -92) {
print("Backspace was pressed")
}
}
return true
}
Older Swift version
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
}
I prefer subclassing UITextField
and overriding deleteBackward()
because that is much more reliable than the hack of using 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()
}
}
The shouldChangeCharactersInRange
hack combined with an invisible character that is placed in the text field has several disadvantages:
Shift Arrow
on a keyboard or even by tapping on the caret) and will be confused about that weird character,placeholder
isn't shown anymore,clearButtonMode = .whileEditing
.Of course, overriding deleteBackward()
is a bit inconvenient due to the need of subclassing. But the better UX makes it worth the effort!
And if subclassing is a no-go, e.g. when using UISearchBar
with its embedded UITextField
, method swizzling should be fine, too.
When the user deletes one or more characters, the replacement string is empty.
So answer for this:
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string.isEmpty {
// do something
}
return true
}
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if range.length > 0 {
// We convert string to NSString instead of NSRange to Range<Int>
// because NSRange and NSString not counts emoji as one character
let replacedCharacters = (string as NSString).substring(with: range)
}
return true
}
class TextField: UITextField {
var backspaceCalled: (()->())?
override func deleteBackward() {
super.deleteBackward()
backspaceCalled?()
}
}
Please don't trash your code. Just put this extension somewhere in your code.
extension String {
var isBackspace: Bool {
let char = self.cString(using: String.Encoding.utf8)!
return strcmp(char, "\\b") == -92
}
}
And then just use it in your functions
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if string.isBackspace {
// do something
}
return true
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With