How can I programmatically dismiss the autocorrect popover in a UITextView?

核能气质少年 提交于 2019-11-30 16:45:30

I tried something similar to yours, but setting the text of the textView this way results in the textView scrolling unnecessarily (my textView contains quite a bit of text). My solution involves restoring the contentOffset in an non-animated fashion. It's not exactly any more elegant than what you have, but at least it helps those who need to deal with longer text.

As for whether it'll continue to work in future, I've tried something like this since iOS 4, and it continues to work through iOS 6.

- (void)rejectAutoCorrectSuggestionInTextView:(UITextView *)textView
{
    if ([textView isFirstResponder])
    {
        NSString *original = textView.text;
        NSRange originalRange = textView.selectedRange;
        CGPoint originalOffset = textView.contentOffset;

        // Force any pending autocorrection to be applied
        [textView resignFirstResponder];
        [textView becomeFirstResponder];

        NSString *final = textView.text;

        if (![original isEqualToString:final])
        {
            textView.text = original;
            textView.selectedRange = originalRange;
            [textView setContentOffset:originalOffset animated:NO];
        }
    }
}

I just encountered this issue myself. This solution works well:

[textView.inputDelegate textWillChange:textView];
[textView.inputDelegate textDidChange:textView];

Your original solution is close. Try the following:

- (void)dismissAutocorrectSuggestionForTextView:(UITextView *)textView {
    NSRange rangeCopy = textView.selectedRange;
    NSString *textCopy = textView.text.copy;
    [textView resignFirstResponder];
    [textView becomeFirstResponder];
    [textView setText:textCopy];
    [textView setSelectedRange:rangeCopy];
}

Calling resign/become first responder back to back causes the text view to accept pending autocorrections immediately, but without actually dismissing the keyboard (try it you'll be surprised). This works on iOS 6 and iOS 7 for sure. After accepting the autocorrections, you then reset the text and the selected range to what they were prior to the autocorrections.

If resigning first responder from text view is unwanted and you can attach as a delegate to the text view, you could implement method

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text

and return NO in a specific case. For example, you could try the following:

@implementation
{
    BOOL _denyReplacements;
}

//////////////

- (void)dismissAutocorrectSuggestionForTextView:(UITextView *)textView {
    NSRange rangeCopy = textView.selectedRange;
    NSRange fakeRange = rangeCopy;
    fakeRange.location--;
    _denyReplacements = YES;
    [textView unmarkText];
    [textView setSelectedRange:fakeRange];
    [textView setSelectedRange:rangeCopy];
    _denyReplacements = NO;
}

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
     return !_denyReplacements;
}

When text view selection changes, autocompletion attempts to accept current suggestion, but text view consults this method before making replacements. An example of why would you do this instead of just resigning/becoming first responder is when you have some logic in textViewDidBeginEditing and/or textViewDidEndEditing methods, for example, which you don't want to be performed when you dismiss the autocorrection.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!