【问题标题】:How to simulate the delete key on UITextField?如何模拟 UITextField 上的删除键?
【发布时间】:2011-03-01 18:39:14
【问题描述】:

我正在 iPad 上创建一个应用程序。我使用UITextFieldinputView 属性创建了一个自定义键盘。要在光标位置插入文本,我使用复制和粘贴方法 (http://dev.ragfield.com/2009/09/insert-text-at-current-cursor-location.html),效果很好。现在,我想创建删除键。我正在使用的代码是:

if (textField.text.length > 0) {
    textField.text = [textField.text substringToIndex:textField.text.length-1];
}

但是,您可能知道,无论光标在哪里,它都只会删除最后一个字符。有谁知道更好的解决方案?

非常感谢!

【问题讨论】:

    标签: iphone ipad cocoa-touch uitextfield


    【解决方案1】:

    考虑切换到UITextView,它具有selectedRange 属性,用于获取当前选定的字符范围或光标位置(如果未选择任何内容)。可惜UITextField没有这个方法,我也没有找到另一种找到光标位置的方法。

    selectedRange 属性的文档可在此处here on Apple's website 找到。它由NSRange 组成,其中selectedRange.location 是光标位置,selectedRange.length 是选定字符的数量(如果未选择任何字符,则为零。)您的代码必须如下所示:

    textView.text = [textView.text stringByReplacingCharactersInRange:textView.selectedRange withString:@""];
    

    【讨论】:

    • 嗨,汤姆。非常感谢。但是,我在 UISearchBar 中使用 UITextField,我认为我不能将其更改为 UITextView。无论如何,我会尝试使用 UITextView 实现我自己的搜索栏。再次感谢您。
    【解决方案2】:

    一个 UITextView 有一个 selectedRange 属性。鉴于您可以构建一个与以下代码一起使用的范围:

    textView.text = [textView.text stringByReplacingCharactersInRange:?? withString:@""];
    

    UITextField 没有这样的范围属性。显然它有一个_selectionRange 成员,但这是私有的。

    我认为您的选择是切换到 UITextView 或阻止光标位于文本末尾以外的任何位置并使用您当前的代码。

    您可以随时向 Apple 提交错误报告,要求他们为 UITextField 记录 selectedRange,或者请求获得直接访问该字段的特殊权限。

    【讨论】:

    • 非常感谢。但是,一个问题是我正在使用 UISearchBar,它只包含一个 UITextField。我可能会使用 UITextView 实现自己的搜索栏,但是我在 Apple 的搜索栏中缺少一些功能,例如范围过滤器和文本字段的外观(即非常圆角)。无论如何,非常感谢。我会尝试你的建议。我从来不知道我们可以请求使用私有 API 的许可。
    • 你可以试试 textView.layer.cornerRadius 的圆角。这需要一些工作,但您可以将文本视图直接放在搜索栏上,这样文本视图就有焦点,但在其他方面很清晰,看起来搜索栏有焦点。
    【解决方案3】:

    我明白了! 这是我的shouldChangeCharactersInRange 方法的委托方法实现。


    - (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange) range replacementString:(NSString *) string {
        if ([string isEqualToString:@"⌫"]) {
            // NSLog(@"Backspace Pressed");
            NSMutableString *text = [textField.text mutableCopy];
            // NSLog(@"Length: %d Location: %d", range.length, range.location);
            if (range.length > 0) {
                [text deleteCharactersInRange:range];
            }
            if (range.length == 0 && range.location != 0) {
                NSRange backward = NSMakeRange(range.location - 1, 1);
                // NSLog(@"Length: %d Location: %d", backward.length, backward.location);
                [text deleteCharactersInRange:backward];
            }
            // NSLog(@"%@", text);
            textField.text = text;
            return NO;
        } else {return YES;}
    }
    

    它与 UIPasteboard method 一起工作,将文本放入 UITextField,这意味着您必须将删除键链接到将任意 unicode 字符粘贴到文本字段中的方法(例如 @987654325 @),并且当调用委托方法时,您会识别出替换字符串是该特定字符。

    从那里,如果有活动选择,您可以从 textField 文本的可变字符串中删除 range 中的字符,或者如果没有选择,则从范围中获取前一个字符,只是一个插入符号。

    【讨论】:

      【解决方案4】:

      这是使用未记录 API 的替代解决方案:selectionRange。我不知道这是否会通过 Apple 的审核,但正如所写的那样,如果该方法不可用并且也没有发出警告,它不会使应用程序崩溃:)

      这是UITextField:上的一个类别

      - (void)deleteBackward{
          @try{
              //check current selected range
              NSRange selectedRange = [[self valueForKey:@"selectionRange"] rangeValue];
              if (selectedRange.location == NSNotFound) selectedRange = NSMakeRange([[self text] length], 0);
              if (selectedRange.location < 1) return;
      
              //delete one char
              NSRange deleteRange = (selectedRange.length>0)?selectedRange:NSMakeRange(selectedRange.location-1,1);
              self.text = [self.text stringByReplacingCharactersInRange:deleteRange withString:@""];
      
              //adjust the selected range to reflect the changes
              selectedRange.location = deleteRange.location;
              selectedRange.range.length = 0;
              [self setValue:[NSValue valueWithRange:range] forKey:@"selectionRange"];
           }@catch (NSException *exception) {
                NSLog(@"failed but catched. %@", exception);
           }@finally {}
      }
      


      更新:2011/11/17

      在 iOS5 中 UITextField 和 UITextView 符合UITextInput 协议(符合UIKeyInput)所以你可以做[textField deleteBackward]; 这将与键盘上的Del 键完全相同,[textField insertText:@"text"]; 将插入文本并正确更新插入符号位置等。

      因此,出于兼容性目的,您可能想要做的类似于此:

      - (void) myDeleteBackward
      {
          if ([self conformsToProtocol:@protocol(UITextInput)]) {
              // iOS5 and later
              [textField deleteBackward];
              // Or do below line if you are not deploy-targeting 5.0 or above and want to avoid warnings
              //[textField performSelector:@selector(deleteBackward)];
          } else {
              // iOS4 and older versions
              // Do the trick :)
              @try{
              ...
              }@catch (NSException *exception) {
              ...
              }
          }
      }
      

      【讨论】:

      • 知道这是否通过了 Apple 审查?这对我来说似乎是一个很好的解决方案
      • 值得尝试 :) 我认为这真的取决于应用程序。有时它们允许应用程序使用未记录的 API。
      • 在 iphone 模拟器 iOS 4.3 上,UITextField 不响应选择器:deleteBackward 但它响应 insertText:.??????
      【解决方案5】:

      神圣的死灵,蝙蝠侠!这是 iOS 3.2 及更高版本的更简单的答案。在您的视图控制器的viewDidLoad 或其他可以访问删除按钮的方法中执行此操作:

      [self.myDeleteButton addTarget:nil action:@selector(deleteBackward) forControlEvents:UIControlEventTouchDown];
      

      这与系统键盘的删除键的工作方式相同:它沿着响应者链发送deleteBackward 消息。

      【讨论】:

        【解决方案6】:

        这个if (UITextField.text.length &gt; 0) { [UITextField deleteBackward]; } 怎么样 :)

        【讨论】:

          【解决方案7】:

          迟到了(再次 ;-)... 在 iOS 5 中,UITextField 符合 UITextInput protocol,它通过一些有用的方法和属性扩展了 UITextField,包括 selectedTextRange 属性,它是相当于UITextView中的selectedRange

          【讨论】:

            【解决方案8】:

            你可以试试这个:

            if (txtTotal.text.length > 0) {
                    txtTotal.text = [txtTotal.text substringToIndex:txtTotal.text.length-1];
                }
            

            【讨论】:

            • 投反对票并举报。问题是关于如何删除任何符号,而不仅仅是最后一个
            【解决方案9】:

            只需致电[textField deleteBackward]。它会为您处理光标位置和突出显示。

            【讨论】:

            • 这其实是一个不错的解决方案。不敢相信我错过了这个。也照顾表情符号。谢谢。 :)
            • 不确定这是否适用于 iPad,我目前看到它适用于 iPhone 但不适用于 iPad...
            • 单行中的出色解决方案...干得好@GoldenJoe
            【解决方案10】:

            要删除光标后面的位置,可以使用textField.deleteBackward()

            当我想在不删除 UITextField 中的文本的情况下获得结果时,这就是我在 Swift 5 中使用的方法

            extension UITextField {
                /// simulates removing a character from 1 position behind the cursor and returns the result
                func backSpace() -> String {
                    guard var text = text, // local text property, matching textField's text
                          let selectedRange = selectedTextRange,
                          !text.isEmpty
                    else { return "" }
                    
                    let offset = offset(from: beginningOfDocument, to: selectedRange.start)
                    
                    let index = text.index(text.startIndex, offsetBy: offset-1)
                    // this doesn't remove text from the textField, just the local text property
                    text.remove(at: index)
                    return text
                }
            }
            

            【讨论】:

              猜你喜欢
              • 2014-10-11
              • 1970-01-01
              • 1970-01-01
              • 2011-07-27
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-02-02
              相关资源
              最近更新 更多