简体   繁体   English

如何模拟UITextField上的delete键?

[英]How to simulate the delete key on UITextField?

I'm creating an application on the iPad.我正在 iPad 上创建一个应用程序。 I create a custom keyboard using UITextField 's inputView property.我使用UITextFieldinputView属性创建了一个自定义键盘。 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. 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.但是,您可能知道,无论 cursor 在哪里,它都只会删除最后一个字符。 Does anyone know a better solution?有谁知道更好的解决方案?

Thank you very much!非常感谢!

Just call [textField deleteBackward] .只需调用[textField deleteBackward] It takes care of cursor position and highlight for you.它会为您处理光标位置和突出显示。

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

I've got it!我懂了! This is my delegate method implementation for the shouldChangeCharactersInRange method.这是我对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;}
}

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.它与UIPasteboard 方法协同工作,用于将文本放入UITextField ,这意味着您必须将删除键链接到将任意 Unicode 字符粘贴到文本字段中的方法(例如 ),并且当委托方法被调用时,您认识到替换字符串是该特定字符。

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

This is an alternative solution using a undocumented API: selectionRange .这是使用未记录的 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 :)我不知道这是否会通过 Apple 的审查,但正如所写的那样,如果该方法不可用并且也不会发出警告,它不会使应用程序崩溃 :)

This is a category on UITextField:这是UITextField:上的一个类别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更新:2011/11/17

in iOS5 UITextField and UITextView conform to UITextInput protocol (which conforms to UIKeyInput ) so you can do [textField deleteBackward];在 iOS5 UITextField 和 UITextView 符合UITextInput协议(符合UIKeyInput )所以你可以做[textField deleteBackward]; which will do exactly the same as Del key in the keyboard, [textField insertText:@"text"];这将与键盘中的Del键完全相同, [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) {
        ...
        }
    }
}

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.考虑切换到UITextView ,它具有selectedRange属性,用于获取当前选定的字符范围或光标位置(如果未选择任何内容)。 Unfortunately, UITextField does not have this method, and I have not found another way to find the cursor location.不幸的是, UITextField没有这个方法,我也没有找到另一种找到光标位置的方法。

The documentation for the selectedRange property can be found here here on Apple's website . selectedRange属性的文档可以在 Apple 网站的此处找到。 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:它由一个NSRange组成,其中selectedRange.location是光标位置, selectedRange.length是所选字符的数量(如果没有选择,则为零。)您的代码必须如下所示:

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

A UITextView has a selectedRange property.一个 UITextView 有一个selectedRange属性。 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. UITextField 没有这样的范围属性。 Obviously it has a _selectionRange member but that is private.显然它有一个_selectionRange成员,但这是私有的。

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.我认为您的选择是切换到 UITextView 或防止将光标置于文本末尾以外的任何位置并使用您当前的代码。

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.您可以随时向 Apple 提交错误报告,要求他们记录 UITextField 的selectedRange ,或请求直接访问该字段的特殊权限。

To delete the position behind the cursor, you can use textField.deleteBackward()要删除光标后面的位置,可以使用textField.deleteBackward()

This is what I use in Swift 5 when I want to get the result without deleting text from the UITextField当我想在不从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
    }
}

Swift 5: Swift 5:

textField.deleteBackward()

Holy necro, Batman!神圣的死灵,蝙蝠侠! Here's a much simpler answer for iOS 3.2 and later.对于 iOS 3.2 及更高版本,这是一个更简单的答案。 Do this in your view controller's viewDidLoad or some other method that has access to the delete button:在视图控制器的viewDidLoad或其他可以访问删除按钮的方法中执行此操作:

[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.这与系统键盘的删除键的工作方式相同:它沿响应者链发送deleteBackward消息。

you can try this:你可以试试这个:

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

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

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

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