[英]Detect backspace Event in UITextField
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.我正在寻找有关如何捕获退格事件的解决方案,大多数 Stack Overflow 答案都在 Objective-C 中,但我需要 Swift 语言。
First I have set delegate for the UITextField and set it to self首先,我为 UITextField 设置了委托并将其设置为 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.然后我知道使用
shouldChangeCharactersInRange
委托方法来检测是否按下退格键是所有代码都在 Objective-C 中。 I need in Swift these following method as below is used.我需要在 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;
}
Swift 4.2斯威夫特 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较旧的 Swift 版本
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
:我更喜欢
deleteBackward()
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()
}
}
The shouldChangeCharactersInRange
hack combined with an invisible character that is placed in the text field has several disadvantages: shouldChangeCharactersInRange
hack 结合放置在文本字段中的不可见字符有几个缺点:
Shift Arrow
on a keyboard or even by tapping on the caret) and will be confused about that weird character,Shift Arrow
,甚至通过点击插入符号),并且会对那个奇怪的字符感到困惑,placeholder
isn't shown anymore,placeholder
,clearButtonMode = .whileEditing
.clearButtonMode = .whileEditing
显示清除按钮。 Of course, overriding deleteBackward()
is a bit inconvenient due to the need of subclassing.当然,由于需要子类化,覆盖
deleteBackward()
有点不方便。 But the better UX makes it worth the effort!但更好的 UX 让它值得付出努力!
And if subclassing is a no-go, eg when using UISearchBar
with its embedded UITextField
, method swizzling should be fine, too.如果子类化是
UISearchBar
,例如,当使用UISearchBar
及其嵌入的UITextField
,方法混合也应该没问题。
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
}
In Swift 3在斯威夫特 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
}
:) :)
Try this尝试这个
public func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
if(string == "") {
print("Backspace pressed");
return true;
}
}
Note: You can return " true " if you want to allow backspace.注意:如果你想允许退格,你可以返回“ true ”。 Else you can return " false ".
否则你可以返回“ false ”。
If u need detect backspace even in empty textField (for example in case if u need auto switch back to prev textField on backSpace pressing), u can use combination of proposed methods - add invisible sign and use standard delegate method textField:shouldChangeCharactersInRange:replacementString:
like follow如果您需要在空的 textField 中检测退格(例如,如果您需要在按下退格键时自动切换回上一个 textField),您可以使用建议的方法组合 - 添加不可见符号并使用标准委托方法
textField:shouldChangeCharactersInRange:replacementString:
喜欢关注
Create invisible sign创建隐形标志
private struct Constants { static let InvisibleSign = "\\u{200B}" }
Set delegate for textField为 textField 设置委托
textField.delegate = self
On event EditingChanged
check text and if needed add invisible symbol like follow:在事件
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 } } }
Add implementation of delegate method textField:shouldChangeCharactersInRange:replacementString:
添加委托方法
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 } }
I implemented this feature:我实现了这个功能:
And in the case where the last textFiled is empty, I just want to switch to the previous textFiled.而在最后一个 textFiled 为空的情况下,我只想切换到上一个 textFiled。 I tried all of the answers above, but no one works fine in my situation.
我尝试了上面的所有答案,但没有一个在我的情况下工作正常。 For some reason, if I add more logic than
print
in isBackSpace == -92
parentheses block this method just stopped work...出于某种原因,如果我在
isBackSpace == -92
括号中添加比print
更多的逻辑,则此方法只会停止工作...
As for me the method below more elegant and works like a charm:至于我,下面的方法更优雅,而且效果很好:
Swift迅速
class YourTextField: UITextField {
// MARK: Life cycle
override func awakeFromNib() {
super.awakeFromNib()
}
// MARK: Methods
override func deleteBackward() {
super.deleteBackward()
print("deleteBackward")
}
}
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
}
}
I find the comparison using strcmp
irrelevant.我发现使用
strcmp
的比较无关紧要。 We don't even know how strcmp
is operating behind the hoods.In all the other answers when comparing current char and \\b
results are -8
in objective-C and -92
in Swift.我们甚至不知道
strcmp
在幕后是如何运作的。在比较当前 char 和\\b
所有其他答案中,objective-C 中的结果为-8
,Swift 中的结果为-92
。 I wrote this answer because the above solutions did not work for me.我写这个答案是因为上述解决方案对我不起作用。 ( Xcode Version
9.3 (9E145)
using Swift 4.1
) (使用 Swift
4.1
Xcode 版本9.3 (9E145)
)
FYI : Every character that you actually type is an array of 1
or more elements in utf8 Encoding
.仅供参考:您实际键入的每个字符都是
utf8 Encoding
中1
或多个元素的数组。 backSpace Character is [0]
.退格字符是
[0]
。 You can try this out.你可以试试这个。
PS : Don't forget to assign the proper delegates
to your textFields
. PS:不要忘记为您的
textFields
分配适当的delegates
。
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斯威夫特 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 4: If the user presses the backspace button, string is empty so this approach forces textField to only accept characters from a specified character set (in this case utf8 characters) and backspaces (string.isEmpty case). 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
}
}
Swift 5: Per the text view delegate documentation , if the replacement text returned by the shouldChangeTextIn method is empty, the user pressed the backspace button. Swift 5:根据文本视图委托文档,如果 shouldChangeTextIn 方法返回的替换文本为空,则用户按下退格按钮。 If the range upper bound is greater than the range lower bound (or range count is 1 or more), text should be deleted.
如果范围上限大于范围下限(或范围计数为 1 或更多),则应删除文本。 If the range upper and lower bounds are the same (or both equal 0), then there is no text to delete (a range of length 0 to be replaced by nothing).
如果范围上限和下限相同(或都等于 0),则没有要删除的文本(长度为 0 的范围将被替换为空)。 I tested, and this will get called even on an empty textfield.
我测试过,即使在空文本字段上也会调用它。
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
}
I came here looking for an answer of how to detect deletions.我来这里是为了寻找如何检测删除的答案。 I wanted to know when the UITextView was empty after a user taps
delete
.我想知道用户点击后 UITextView 何时为空
delete
。 As I was testing, I realized I needed to capture whole word deletions and cuts as well.在测试时,我意识到我还需要捕获整个单词的删除和删减。 Here's the answer I came up with.
这是我想出的答案。
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
}
}
Thanks for all the previous helpful answers.感谢之前所有有用的答案。 I hope this helps someone.
我希望这可以帮助别人。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.