简体   繁体   English

如何检测 iOS 8 中 UITextField 上的删除键?

[英]How to detect delete key on an UITextField in iOS 8?

I have subclassed UITextField and implemented the UIKeyInput protocol's deleteBackward method to detect backspace being pressed.我已经继承了 UITextField 并实现了 UIKeyInput 协议的 deleteBackward 方法来检测被按下的退格。 This works fine on iOS 7 but not on iOS 8.这在 iOS 7 上运行良好,但在 iOS 8 上不起作用。

deleteBackward is not called on the UITextField anymore when I press the backspace key.当我按下退格键时,不再在 UITextField 上调用 deleteBackward。

I've checked the documentation and the release notes and nothing points to the reason why this could happen.我已经检查了文档和发行说明,但没有指出发生这种情况的原因。 Any pointers?任何指针?

A lot of people have been saying this is a bug, but being that this problem still exists in the GM I'm starting to think it might be a change in logic.很多人一直说这是一个错误,但由于这个问题仍然存在于 GM 中,我开始认为这可能是逻辑上的变化。 With that said, I wrote this bit of code for my app and have tested it on iOS 7-8.话虽如此,我为我的应用程序编写了这段代码,并在 iOS 7-8 上对其进行了测试。

Add the following method to your UITextField subclass.将以下方法添加到您的UITextField子类中。

- (BOOL)keyboardInputShouldDelete:(UITextField *)textField {
    BOOL shouldDelete = YES;

    if ([UITextField instancesRespondToSelector:_cmd]) {
        BOOL (*keyboardInputShouldDelete)(id, SEL, UITextField *) = (BOOL (*)(id, SEL, UITextField *))[UITextField instanceMethodForSelector:_cmd];

        if (keyboardInputShouldDelete) {
            shouldDelete = keyboardInputShouldDelete(self, _cmd, textField);
        }
    }

    BOOL isIos8 = ([[[UIDevice currentDevice] systemVersion] intValue] == 8);
    BOOL isLessThanIos8_3 = ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.3f);

    if (![textField.text length] && isIos8 && isLessThanIos8_3) {
        [self deleteBackward];
    }

    return shouldDelete;
}

This code is slightly before the red line of private API's, however you should have no problem using it.这段代码略在私有 API 的红线之前,但是您使用它应该没有问题。 My app with this code is in the app store.我使用此代码的应用程序在应用程序商店中。

To explain a little, were calling the super implementation of this method to avoid losing code.稍微解释一下,正在调用此方法的超级实现以避免丢失代码。 After were going to call -deleteBackward if there is no text and the iOS version is between 8-8.2.后,要打电话-deleteBackward如果没有文字和iOS版本的8-8.2之间。

EDIT : 1/22/15编辑:1/22/15

It also might be helpful to subclass the -deleteBackward method of your subclassed UITextField .将子类化的UITextField-deleteBackward方法子类化也可能会有所帮助。 This fixes a few conditional bugs.这修复了一些条件错误。 One being if you use a custom keyboard.一个是如果您使用自定义键盘。 Heres an example of the method.这是该方法的示例。

- (void)deleteBackward {
    BOOL shouldDismiss = [self.text length] == 0;

    [super deleteBackward];

    if (shouldDismiss) {
        if ([self.delegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
            [self.delegate textField:self shouldChangeCharactersInRange:NSMakeRange(0, 0) replacementString:@""];
        }
    }
}

EDIT : 4/13/15编辑:4/13/15

As @Gee.E commented, iOS 8.3 has fixed this issue.正如@Gee.E 评论的那样,iOS 8.3 已经修复了这个问题。 The code has been updated to reflect the changes.代码已更新以反映更改。

You can detect when user deletes text by using backspace by implementing UITextField delegate method:您可以通过实现 UITextField 委托方法来检测用户何时使用退格键删除文本:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (range.length==1 && string.length==0)
        NSLog(@"backspace tapped");

    return YES;
}

You must look an example for MBContactPicker on github.您必须在 github 上查看MBContactPicker的示例。 Deletion of contacts at MBContactPicker via Backspace button on iOS8 tested by me.通过我测试的 iOS8 上的 Backspace 按钮删除 MBContactPicker 上的联系人。 And it works greatly!而且效果很好! You can use its as example.你可以用它作为例子。

Author of MBContactPicker use next method: When UITextField must become empty (or before call becomeFirstResponder when it is empty), he save single whitespace symbol there. MBContactPicker 的作者使用 next 方法:当 UITextField 必须为空时(或在为空时调用 becomeFirstResponder 之前),他将单个空格符号保存在那里。 And then when you press Backspace button (when focus was set to end of text of your UITextField), method然后当您按下 Backspace 按钮时(当焦点设置为 UITextField 的文本结尾时),方法

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string

will work.将工作。 Inside it you must use check like this:在它里面你必须像这样使用检查:

NSString *resultString = [textField.text stringByReplacingCharactersInRange:range withString:string];
BOOL isPressedBackspaceAfterSingleSpaceSymbol = [string isEqualToString:@""] && [resultString isEqualToString:@""] && range.location == 0 && range.length == 1;
if (isPressedBackspaceAfterSingleSpaceSymbol) {
    //  your actions for deleteBackward actions
}

So, you must always control that UITextField contains single whitespace.因此,您必须始终控制 UITextField 包含单个空格。

This is not hack.这不是黑客攻击。 So, user willn't noticed about some behaviour was changed因此,用户不会注意到某些行为已更改

Swift 2.2:斯威夫特 2.2:

func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {

    if text == "" {
      print("Backspace has been pressed")
    }

    return true
}

In iOS8, some custom keyboards delete whole word, so only check string.length is OK.在 iOS8 中,一些自定义键盘会删除整个单词,所以只检查 string.length 就可以了。

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    if (string.length==0) { //Delete any cases
       if(range.length > 1){
          //Delete whole word
       }
       else if(range.length == 1){
          //Delete single letter
       }
       else if(range.length == 0){
          //Tap delete key when textField empty
       }  
    }  
    return YES;
}

This does not explicitly answer the original question but worth nothing that in the documentation for textField(_:shouldChangeCharactersIn:replacementString:) , it says:这并没有明确回答原始问题,但在textField(_:shouldChangeCharactersIn:replacementString:)的文档中没有任何价值,它说:

" string : The replacement string for the specified range. During typing, this parameter normally contains only the single new character that was typed, but it may contain more characters if the user is pasting text. When the user deletes one or more characters, the replacement string is empty." " string : 指定范围的替换字符串。在输入过程中,该参数通常只包含输入的单个新字符,但如果用户粘贴文本,它可能包含更多字符。当用户删除一个或多个字符时,替换字符串为空。”

Thus, we can detect backspaces in a UITextFieldDelegate if we implement textField(_:shouldChangeCharactersIn:replacementString:) and check if the length of string is 0.因此,如果我们实现textField(_:shouldChangeCharactersIn:replacementString:)并检查string的长度是否为 0,我们可以检测UITextFieldDelegate退格。

A lot of other answers here have used this same logic without referencing the documentation so hopefully getting it right from the source makes people more comfortable using it.这里的许多其他答案都使用了相同的逻辑,而没有参考文档,因此希望从源头获取正确的信息可以让人们更舒适地使用它。

Swift 2.0 version for Detecting BackSpace based deletion, referencing code post from almas Swift 2.0 版本,用于检测基于 BackSpace 的删除,引用来自 almas 的代码帖子

//For Detecting Backspace based Deletion of Entire Word in TextField
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { 
    if (range.length == 1 && string.isEmpty){
        print("Used Backspace")
    }
return true
}
- (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;

}

Basically this method detects which button you are pressing (or have just pressed).基本上,此方法会检测您正在按下(或刚刚按下)哪个按钮。 This input comes in as an NSString.此输入作为 NSString 出现。 We convert this NSString to a C char type and then compare it to the traditional backspace character (\\b).我们将此 NSString 转换为 C 字符类型,然后将其与传统的退格字符 (\\b) 进行比较。 Then if this strcmp is equal to -8, we can detect it as a backspace.然后如果这个 strcmp 等于 -8,我们可以将它检测为退格。

swift 2:快速2:

if (string.characters.count == 0 && range.length == 1) {
            return true
}

you should use like this string.characters.count你应该像这样使用string.characters.count

func keyboardInputShouldDelete(_ textField: UITextField) -> Bool { } func keyboardInputShouldDelete(_ textField: UITextField) -> Bool { }

This function is called when you hit delete key当您按下删除键时调用此函数

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM