Остановить UITextView от прыжка при программной настройке текста - PullRequest
19 голосов
/ 14 мая 2009

Мне нужно обновить небольшое количество текста в прокручиваемом UITextView. Я буду вставлять символ только там, где в данный момент находится курсор, и буду делать это нажатием кнопки на панели навигации.

Моя проблема в том, что всякий раз, когда я вызываю метод setText текстового представления, он переходит в конец текста. Я пытался использовать contentOffset и сбрасывать selectedRange, но это не работает! Вот мой пример:

// Remember offset and selection
CGPoint contentOffset = [entryTextView contentOffset];
NSRange selectedRange = [entryTextView selectedRange];
// Update text
entryTextView.text = entryTextView.text;
// Try and reset offset and selection
[entryTextView setContentOffset:contentOffset animated:NO];
[entryTextView setSelectedRange: selectedRange];

Можно ли каким-либо образом обновить текст без какого-либо движения прокрутки ... как если бы они просто что-то набрали на клавиатуре?

Edit:

Я пытался использовать метод textViewDidChange: делегат, но он все еще не прокручивается до исходного местоположения.

- (void)textViewDidChange:(UITextView *)textView {
    if (self.programChanged) {
        [textView setSelectedRange:self.selectedRange];
        [textView setContentOffset:self.contentOffset animated:NO];
        self.programChanged = NO;
    }
}

- (void)changeButtonPressed:(id)sender {
    // Remember position
    self.programChanged = YES;
    self.contentOffset = [entryTextView contentOffset];
    self.selectedRange = [entryTextView selectedRange];
    // Update text
    entryTextView.text = entryTextView.text;
}

Ответы [ 13 ]

14 голосов
/ 03 мая 2010

Если вы используете iPhone 3.0 или новее, вы можете решить эту проблему:

textView.scrollEnabled = NO;

//You should know where the cursor will be(if you update your text by appending/inserting/deleting you can know the selected range) so keep it in a NSRange variable.

Then update text:
textView.text = yourText;

textView.scrollEnabled = YES;
textView.selectedRange = range;//you keep before

Теперь должно работать (больше не надо прыгать)

С уважением Меир Ассаяг

8 голосов
/ 15 августа 2010

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

NSRange selectedRange = textView.selectedRange;
textView.scrollEnabled = NO;
// I'm deleting text. Replace this line with whatever insertions/changes you want
textView.text = [textView.text
                stringByReplacingCharactersInRange:selectedRange withString:@""];
selectedRange.length = 0;
// If you're inserting text, you might want to increment selectedRange.location to be
// after the text you inserted
textView.selectedRange = selectedRange;
textView.scrollEnabled = YES;
6 голосов
/ 29 января 2015

Это решение работает для iOS 8:

let offset = textView.contentOffset
textView.text = newText
textView.layoutIfNeeded()
textView.setContentOffset(offset, animated: false)

Необходимо вызвать точно setContentOffset:animated:, потому что только это отменит анимацию. textView.contentOffset = offset не отменит анимацию и не поможет.

4 голосов
/ 07 января 2015

Следующие два решения не работают для меня на iOS 8.0.

textView.scrollEnabled = NO;
[textView.setText: text];
textView.scrollEnabled = YES;

и

CGPoint offset = textView.contentOffset;
[textView.setText: text];
[textView setContentOffset:offset];

Я настроил делегата в textview для наблюдения за событием прокрутки и заметил, что после моей операции по восстановлению смещения смещение снова сбрасывается до 0. Поэтому я вместо этого использую основную очередь операций, чтобы убедиться, что моя операция восстановления происходит после параметра «сброс к 0».

Вот мое решение, которое работает для iOS 8.0.

CGPoint offset = self.textView.contentOffset;
self.textView.attributedText = replace;
[[NSOperationQueue mainQueue] addOperationWithBlock: ^{
    [self.textView setContentOffset: offset];
}];
3 голосов
/ 08 февраля 2015

Чтобы отредактировать текст UITextView, вам необходимо обновить его поле textStorage:

[_textView.textStorage beginEditing];

NSRange replace = NSMakeRange(10, 2); //enter your editing range
[_textView.textStorage replaceCharactersInRange:replace withString:@"ha ha$ "];

//if you want to edit the attributes
NSRange attributeRange = NSMakeRange(10, 5); //enter your editing attribute range
[_textView.textStorage addAttribute:NSBackgroundColorAttributeName value:[UIColor greenColor] range:attributeRange];

[_textView.textStorage endEditing];

Удачи

3 голосов
/ 20 июля 2010

Ни одно из предложенных решений не сработало для меня. -setContentOffset: animated: запускается по -setText: 3 раза с анимированным YES и contentOffset конца (за вычетом стандартного поля 8pt для UITextView) Я завернул -setText: в охранник:

textView.contentOffsetAnimatedCallsDisabled = YES;
textView.text = text;
textView.contentOffsetAnimatedCallsDisabled = NO;

В подклассе UITextView в -setContentOffset: animated: put

if (contentOffsetAnimatedCallsDisabled) return; // early return

среди вашей другой логики. Не забывайте супер звонок. Это работает.

Raphael

2 голосов
/ 25 апреля 2014

в iOS 7. Похоже, ошибка в sizeThatFits и разрывы строк в вашем UITextView. Решение, которое я нашел, работает, чтобы обернуть его, отключив прокрутку. Как это:

textView.scrollEnabled = NO;
CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
textView.scrollEnabled = YES;

и странные прыжки были исправлены.

1 голос
/ 02 сентября 2017

Наконец попробуйте это, проверено на iOS 10

let offset = textView.contentOffset
textView.attributedText = newValue
OperationQueue.main.addOperation {
    self.textView.setContentOffset(offset, animated: false)
}
1 голос
/ 19 июня 2016

Я столкнулся с похожей, если не той же проблемой в IOS9. Изменение характеристик некоторого текста, скажем, на BOLD, привело к тому, что представление прокрутило выделение вне поля зрения. Я отсортировал это, добавив вызов scrollRangeToVisible после setSelectedRange:

    [self setSelectedRange:range];
    [self scrollRangeToVisible:range];
1 голос
/ 06 февраля 2014

Старый вопрос, но у меня была та же проблема с приложением iOS 7. Требуется изменить contentOffset немного позже цикла выполнения. Вот быстрая идея.

self.clueString = [self.level clueText];
CGPoint point = self.clueText.contentOffset;
self.clueText.attributedText = self.clueString;
double delayInSeconds = 0.001; // after the run loop update
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    [self.clueText setContentOffset:point animated:NO]; 
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...