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

VNV*_*NVN 38 uitextfield ios uitextfielddelegate uikeyinput ios8

我已经将UITextField子类化,并实现了UIKeyInput协议的deleteBackward方法来检测被按下的退格.这适用于iOS 7,但不适用于iOS 8.

当我按退格键时,不再在UITextField上调用deleteBackward.

我已经检查了文档和发行说明,没有指出可能发生这种情况的原因.有什么指针吗?

cno*_*gr8 47

很多人一直在说这是一个错误,但由于这个问题在GM中仍然存在,我开始认为它可能是逻辑上的变化.话虽如此,我为我的应用程序编写了这段代码,并在iOS 7-8上进行了测试.

将以下方法添加到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;
}
Run Code Online (Sandbox Code Playgroud)

此代码稍微位于私有API的红线之前,但是使用它时应该没有问题.我的应用程序使用此代码在应用程序商店中.

为了解释一下,正在调用此方法的超级实现以避免丢失代码.-deleteBackward如果没有文本,那么打电话后,iOS版本介于8-8.2之间.

编辑:2015年1月22日

子类化子类的-deleteBackward方法也可能有所帮助UITextField.这修复了一些有条件的错误.一种是如果你使用自定义键盘.这是该方法的一个例子.

- (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:@""];
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:4/13/15

正如@ Gee.E评论的那样,iOS 8.3已经解决了这个问题.代码已更新以反映更改.

  • 似乎这个bug在iOS 8.3中得到了解决,因为`-deleteBackward`调用现在已经通过了(没有来自这个答案的代码) (5认同)
  • 这个应该被接受作为正确的答案,并且完美地作为一种解决方法,而ios8错误(https://devforums.apple.com/message/1009150#1009150)仍然存在. (4认同)
  • @Miszy啊,是的,你必须继承`-deleteBackward`.我用我的应用程序中使用的内容更新答案. (2认同)

alm*_*mas 22

您可以通过实现UITextField委托方法来检测用户何时使用退格键删除文本:

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

    return YES;
}
Run Code Online (Sandbox Code Playgroud)

  • 如果文本字段的文本为空,则不会检测退格.deleteBackward是在所有情况下检测退格的方法,但是在iOS 8上不再被调用..在空文本字段的情况下如何检测任何想法? (14认同)

iVa*_*der 12

你必须在github上查看MBContactPicker的示例.通过我测试的iOS8上的Backspace按钮删除MBContactPicker上的联系人.而且效果很好!您可以使用它作为示例.

MBContactPicker的作者使用next方法:当UITextField必须为空时(或者在它为空时调用becomeFirstResponder之前),他在那里保存单个空白符号.然后当您按Backspace按钮时(当焦点设置为UITextField的文本结尾时),方法

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
Run Code Online (Sandbox Code Playgroud)

将工作.在里面你必须使用这样的支票:

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
}
Run Code Online (Sandbox Code Playgroud)

因此,您必须始终控制UITextField包含单个空格.

这不是黑客攻击.因此,用户不会注意到某些行为已被更改

  • 这是黑客的定义.但这并不意味着黑客行不通. (8认同)

LE *_*ANG 6

在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;
}
Run Code Online (Sandbox Code Playgroud)


Vla*_*iak 6

Swift 2.2:

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

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

    return true
}
Run Code Online (Sandbox Code Playgroud)