ios 检测 UITextField 中的退格事件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29504304/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 05:34:00  来源:igfitidea点击:

Detect backspace Event in UITextField

iosswiftcocoa-touchuikituitextfielddelegate

提问by Want Query

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 shouldChangeCharactersInRangedelegate 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.

然后我知道使用shouldChangeCharactersInRange委托方法来检测是否按下了退格键,所有代码都在 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;
}

回答by Long Pham

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
}

回答by Ortwin Gentz

I prefer subclassing UITextFieldand overriding deleteBackward()because that is much more reliable than the hack of using shouldChangeCharactersInRange:

我更喜欢子类化UITextField和覆盖,deleteBackward()因为这比使用 hack 可靠得多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 shouldChangeCharactersInRangehack combined with an invisible character that is placed in the text field has several disadvantages:

shouldChangeCharactersInRange黑客与被放置在文本字段中有不可见字符组合有几个缺点:

  • with a keyboard attached, one can place the cursor before the invisible character and the backspace isn't detected anymore,
  • the user can even select that invisible character (using Shift Arrowon a keyboard or even by tapping on the caret) and will be confused about that weird character,
  • the autocomplete bar offers weird choices as long as there's only this invisible character,
  • Asian language keyboards that have candidate options based on the text field's text will be confused,
  • the placeholderisn't shown anymore,
  • the clear button is displayed even when it shouldn't for clearButtonMode = .whileEditing.
  • 连接键盘后,可以将光标放在不可见字符之前,不再检测到退格,
  • 用户甚至可以选择那个不可见的字符(Shift Arrow在键盘上使用,甚至通过点击插入符号)并且会对那个奇怪的字符感到困惑,
  • 只要只有这个不可见的字符,自动完成栏就会提供奇怪的选择,
  • 具有基于文本字段文本的候选选项的亚洲语言键盘将被混淆,
  • placeholder不再被示出,
  • 即使不应该显示清除按钮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!

当然,deleteBackward()由于需要子类化,覆盖有点不方便。但更好的 UX 让它值得付出努力!

And if subclassing is a no-go, e.g. when using UISearchBarwith its embedded UITextField, method swizzling should be fine, too.

如果子类化是行不通的,例如当使用UISearchBar其嵌入时UITextField,方法 swizzling 也应该没问题。

回答by Insou

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
}

:)

:)

回答by gbk

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:例如 follow

  1. Create invisible sign

    private struct Constants {
        static let InvisibleSign = "\u{200B}"
    }
    
  2. Set delegate for textField

    textField.delegate = self
    
  3. On event EditingChangedcheck text and if needed add invisible symbol like follow:

    @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
            }
        }
    }
    
  1. 创建隐形标志

    private struct Constants {
        static let InvisibleSign = "\u{200B}"
    }
    
  2. 为 textField 设置委托

    textField.delegate = self
    
  3. 在事件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
            }
        }
    }
    

enter image description here

在此处输入图片说明

  1. Add implementation of delegate method 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
        }
    }
    
  1. 添加委托方法的实现 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
        }
    }
    

回答by Dmitry Kozlov

Please don't trash your code. Just put this extension somewhere in your code.

请不要丢弃您的代码。只需将此扩展名放在代码中的某个位置即可。

Swift 5.1

斯威夫特 5.1

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
}

回答by Augustine P A

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. Else you can return "false".

注意:如果你想允许退格,你可以返回“ true”。否则你可以返回“ false”。

回答by Roman Romanenko

I implemented this feature:

我实现了这个功能:

enter image description here

在此处输入图片说明

And in the case where the last textFiled is empty, I just want to switch to the previous 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 printin isBackSpace == -92parentheses block this method just stopped work...

而在最后一个 textFiled 为空的情况下,我只想切换到上一个 textFiled。我尝试了上面的所有答案,但没有一个在我的情况下工作正常。出于某种原因,如果我不是增加更多的逻辑printisBackSpace == -92括号阻止这种方法刚刚停止工作...

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")
    }

}

Thanks @LombaX for the answer

感谢@LombaX 的回答

回答by Amr Angry

Swift 4

斯威夫特 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
            }
}

回答by GreenCamper

Swift 4

斯威夫特 4

I find the comparison using strcmpirrelevant. We don't even know how strcmpis operating behind the hoods.In all the other answers when comparing current char and \bresults are -8in objective-C and -92in Swift. I wrote this answer because the above solutions did not work for me. ( Xcode Version 9.3 (9E145)using Swift 4.1)

我发现使用strcmp不相关的比较。我们甚至不知道strcmp幕后是如何操作的。在比较当前字符和\b结果时,所有其他答案都-8在 Objective-C 和-92Swift 中。我写这个答案是因为上述解决方案对我不起作用。(9.3 (9E145)使用 Swift 的Xcode 版本4.1

FYI :Every character that you actually type is an array of 1or more elements in utf8 Encoding. backSpace Character is [0]. You can try this out.

FYI:你实际键入的每个字符是一个数组1或多个元素utf8 Encoding。退格字符是[0]. 你可以试试这个。

PS :Don't forget to assign the proper delegatesto your textFields.

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
}

回答by Shakeel Ahmed

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
    }
}