【问题标题】:How to detect delete key on an UITextField in iOS 8?如何在 iOS 8 中检测 UITextField 上的删除键?
【发布时间】:2014-10-11 20:03:23
【问题描述】:

我继承了 UITextField 并实现了 UIKeyInput 协议的 deleteBackward 方法来检测退格键被按下。这适用于 iOS 7,但不适用于 iOS 8。

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

我已经检查了文档和发行说明,但没有任何迹象表明会发生这种情况。有什么指点吗?

【问题讨论】:

标签: ios uitextfield ios8 uitextfielddelegate uikeyinput


【解决方案1】:

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

当你点击删除键时调用这个函数

【讨论】:

    【解决方案2】:

    这并没有明确回答原始问题,但在textField(_:shouldChangeCharactersIn:replacementString:) 的文档中毫无价值,它说:

    "string:指定范围的替换字符串。在键入时,该参数通常只包含输入的单个新字符,但如果用户粘贴文本,则可能包含更多字符。当用户删除一个或更多字符,替换字符串为空。”

    因此,如果我们实现textField(_:shouldChangeCharactersIn:replacementString:),我们可以检测UITextFieldDelegate 中的退格,并检查string 的长度是否为0。

    这里的许多其他答案都使用了相同的逻辑,而没有参考文档,因此希望从源头上正确获取它会让人们更舒服地使用它。

    【讨论】:

      【解决方案3】:

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

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

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

      会起作用。在里面你必须像这样使用检查:

      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
      }
      

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

      这不是黑客。因此,用户不会注意到某些行为发生了变化

      【讨论】:

      • 这是黑客的定义。但这并不意味着 hack 不起作用。
      • 在我的定义中,hack 不是原生实现。它很可能禁止实现,这可能会成为 AppStore 方面拒绝您的构建的原因
      • BOOL isPressedBackspaceAfterSingleSpaceSymbol = [resultString isEqualToString:@""];也会起作用
      【解决方案4】:

      斯威夫特 2.2:

      func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
      
          if text == "" {
            print("Backspace has been pressed")
          }
      
          return true
      }
      

      【讨论】:

        【解决方案5】:

        迅速 2:

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

        你应该像这样使用string.characters.count

        【讨论】:

          【解决方案6】:

          用于检测基于 BackSpace 的删除的 Swift 2.0 版本,referencing code post from 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
          }
          

          【讨论】:

          • 测试string.isEmpty 是否是测试删除的正确方法,但range.length == 1 是错误的。如果用户选择了一堆文本并点击删除,则范围长度将大于 1,因为他们正在删除多个字符。
          【解决方案7】:

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

          【讨论】:

            【解决方案8】:
            - (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;
            
            }
            

            基本上,此方法检测您正在按下(或刚刚按下)的按钮。此输入以 NSString 的形式出现。我们将此 NSString 转换为 C char 类型,然后将其与传统的退格字符 (\b) 进行比较。那么如果这个strcmp等于-8,我们就可以把它检测为退格了。

            【讨论】:

              【解决方案9】:

              很多人一直说这是一个错误,但由于这个问题仍然存在于 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;
              }
              

              这段代码略早于私有 API 的红线,但是您使用它应该没有问题。我的带有此代码的应用在应用商店中。

              稍微解释一下,调用此方法的超级实现以避免丢失代码。如果没有文字并且iOS版本在8-8.2之间,之后会打电话给-deleteBackward

              编辑: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:@""];
                      }
                  }
              }
              

              编辑:2015 年 4 月 13 日

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

              【讨论】:

              • 这个应该被接受为正确答案,并且在 ios8 错误 (devforums.apple.com/message/1009150#1009150) 仍然存在时完美地作为一种解决方法。
              • 是的,这适用于 iOS 8,它改变了这种行为(错误与否)。也适用于 UITextView。谢谢!
              • @Miszy 啊,是的,你必须继承 -deleteBackward。我会用我在应用程序中使用的内容更新答案。
              • 现在它可以正常工作了。魔法。感谢您抽出宝贵时间@cnotethegr8! :)
              • 这个错误似乎在 iOS 8.3 中得到了解决,因为 -deleteBackward 调用现在通过(没有来自这个答案的代码)
              【解决方案10】:

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

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

              【讨论】:

              • 不是每次按一个键时都会调用它。我认为您需要检查 range.location == 0 && range.length == 1 && string.length == 0
              • @VNVN,你是正确的 string.length 应该等于 0,我编辑了我的答案。但是,我不确定为什么 range.location 应该是 0?每次都不一样……
              • 你是对的。 range.location 不是必需的。那是针对我的用例的,抱歉!
              • 如果文本字段的文本为空,则不会检测退格。 deleteBackward 是在所有情况下检测退格的方法,但在 iOS 8 上不再被调用。关于在空文本字段的情况下如何检测的任何想法?
              • 它工作正常,推出了它的 Swift 2.0 版本。 //用于检测基于退格键删除 TextField 中的整个单词 func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { if (range.length == 1 && string.isEmpty){ print("使用退格键") } 返回真 }
              猜你喜欢
              • 2011-03-01
              • 2020-08-06
              • 1970-01-01
              • 2016-03-30
              • 2011-07-27
              • 2015-11-22
              • 1970-01-01
              • 2011-08-22
              • 1970-01-01
              相关资源
              最近更新 更多