Как я могу программно отклонить всплывающее окно автозамены в UITextView?

Я делаю некоторые собственные автозаполнения самостоятельно с insertText:, но если есть видимое предложение автозамены, представление переходит в странное состояние.

Если я использую [textView unmarkText], он отклоняет всплывающее окно автозамены - но он принимает автокоррекцию (что плохо). Есть ли какой-нибудь способ программно отклонить предложение автозамены?

Мое текущее "решение" работает, но оно грубое и хакерское, и у меня нет оснований предполагать, что оно продолжит работать в будущем. Есть лучший способ сделать это?

- (void)dismissAutocorrectSuggestionForTextView:(UITextView *)textView {
    NSRange range = textView.selectedRange;
    textView.text = textView.text;
    textView.selectedRange = range;
}

4 ответа

Я пробовал что-то похожее на ваше, но установка текста textView таким образом приводит к ненужной прокрутке textView (мой textView содержит довольно мало текста). Мое решение заключается в восстановлении contentOffset без анимации. Это не совсем более элегантно, чем то, что у вас есть, но, по крайней мере, помогает тем, кому нужно иметь дело с более длинным текстом.

Что касается того, будет ли он продолжать работать в будущем, я пробовал что-то подобное с iOS 4, и он продолжает работать через 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];
        }
    }
}

Я только что столкнулся с этой проблемой сам. Это решение хорошо работает:

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

Ваше оригинальное решение близко. Попробуйте следующее:

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

При повторном вызове в отставку / становлении первым респондентом текстовое представление немедленно принимает ожидающие автокоррекции, но без фактического закрытия клавиатуры (попробуйте, вы будете удивлены). Это работает на iOS 6 и iOS 7 точно. Приняв автокоррекции, вы сбрасываете текст и выбранный диапазон до того, что было до автокоррекции.

Если отставка первого респондента из текстового представления нежелательна, и вы можете присоединиться как делегат к текстовому представлению, вы можете реализовать метод

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

а также return NO в конкретном случае. Например, вы можете попробовать следующее:

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

Когда изменяется выбор текстового представления, автозаполнение пытается принять текущее предложение, но текстовое представление консультируется с этим методом перед выполнением замен. Пример того, почему вы делаете это вместо того, чтобы просто подать в отставку или стать первым респондентом, - это когда у вас есть некоторая логика в textViewDidBeginEditing и / или textViewDidEndEditing методы, например, которые вы не хотите выполнять при отклонении автокоррекции.

Другие вопросы по тегам