如何模拟UITextField上的删除键?

发布于 2024-09-04 13:08:12 字数 544 浏览 3 评论 0 原文

我正在 iPad 上创建一个应用程序。我使用 UITextFieldinputView 属性创建自定义键盘。要在光标位置插入文本,我使用 copy &粘贴方法 (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];
}

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

非常感谢!

I'm creating an application on the iPad. I create a custom keyboard using UITextField's inputView property. To insert text at the cursor position, I use the copy & paste method (http://dev.ragfield.com/2009/09/insert-text-at-current-cursor-location.html), which works fine. Now, I want to create the delete key. The code that I'm using is:

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

However, as you may know, it only deletes the last character no matter where the cursor is. Does anyone know a better solution?

Thank you very much!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

眼泪也成诗 2024-09-11 13:08:12

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

迅速:

textField.deleteBackward()

Just call [textField deleteBackward]. It takes care of cursor position and highlight for you.

Swift:

textField.deleteBackward()
梦萦几度 2024-09-11 13:08:12

我明白了!
这是我的 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 方法 配合使用来获取文本到 UITextField 中,这意味着您必须将删除键链接到将任意 unicode 字符粘贴到文本字段中的方法(例如 ),并且当调用委托方法时,您会认识到替换字符串是该特定字符。

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

I've got it!
This is my delegate method implementation for the shouldChangeCharactersInRange method.


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

It works hand in hand with the UIPasteboard method for getting text into a UITextField, which means that you have to link up your delete key to a method that pastes an arbitrary unicode character into your textfield (such as ), and when the delegate method is called, you recognise that the replacement string is that specific character.

From there, you either delete the characters in range from your mutable string of the textField's text if there is an active selection, or you grab the previous character from the range if there is no selection, just a caret.

享受孤独 2024-09-11 13:08:12

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

Late to the party (again ;-)... With iOS 5, UITextField conforms to the UITextInput protocol, which extends UITextField with some helpful methods and properties, including the selectedTextRange property, which is the equivalent of selectedRange in UITextView.

牵你的手,一向走下去 2024-09-11 13:08:12

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

这是 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) {
        ...
        }
    }
}

This is an alternative solution using a undocumented API: selectionRange. I don't know if this will pass Apple's review but as written it won't make the app crash if the method is not available and does not give warnings too :)

This is a category on 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 {}
}

UPDATE: 2011/11/17

in iOS5 UITextField and UITextView conform to UITextInput protocol (which conforms to UIKeyInput) so you can do [textField deleteBackward]; which will do exactly the same as Del key in the keyboard, [textField insertText:@"text"]; which will insert text and update the caret position correctly, etc.

So, for compatibility purposes, probably what you want to do similar to this:

- (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) {
        ...
        }
    }
}
南冥有猫 2024-09-11 13:08:12

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

selectedRange 属性的文档可以在这里找到 Apple 网站上。它由一个 NSRange 组成,其中 selectedRange.location 是光标位置,selectedRange.length 是所选字符的数量(如果没有则为零)被选中。)您的代码必须如下所示:

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

Consider switching to a UITextView, which has a selectedRange property for getting the currently selected range of characters or the cursor location if nothing is selected. Unfortunately, UITextField does not have this method, and I have not found another way to find the cursor location.

The documentation for the selectedRange property can be found here here on Apple's website. It consists of an NSRange in which selectedRange.location is the cursor location and selectedRange.length is the number of selected characters (or zero if nothing is selected.) Your code will have to look something like this:

textView.text = [textView.text stringByReplacingCharactersInRange:textView.selectedRange withString:@""];
悲歌长辞 2024-09-11 13:08:12

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

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

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

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

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

A UITextView has a selectedRange property. Given that you could build a range to use with the following code:

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

A UITextField has no such range property. Obviously it has a _selectionRange member but that is private.

I think your choices are either to switch to a UITextView or prevent having the cursor anywhere but at the end of the text and using your current code.

You can always submit a bug report to Apple requesting that they document selectedRange for UITextField, or ask for special permission to access the field directly.

野稚 2024-09-11 13:08:12

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

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

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

Holy necro, Batman! Here's a much simpler answer for iOS 3.2 and later. Do this in your view controller's viewDidLoad or some other method that has access to the delete button:

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

This is the same way the system keyboard's delete key works: it sends the deleteBackward message along the responder chain.

不交电费瞎发啥光 2024-09-11 13:08:12

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

这是我在 Swift 5 中使用的方法,当我想获取结果而不从 UITextField 中删除文本时>

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

To delete the position behind the cursor, you can use textField.deleteBackward()

This is what I use in Swift 5 when I want to get the result without deleting text from the UITextField

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
    }
}
海的爱人是光 2024-09-11 13:08:12

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

What about this if (UITextField.text.length > 0) { [UITextField deleteBackward]; } :)

末が日狂欢 2024-09-11 13:08:12

你可以试试这个:

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

you can try this:

if (txtTotal.text.length > 0) {
        txtTotal.text = [txtTotal.text substringToIndex:txtTotal.text.length-1];
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文