Остановить UITextView от прыжка при программном настройке текста
Мне нужно обновить небольшое количество текста в прокручиваемом UITextView. Я буду только вставлять символ, в котором сейчас находится курсор, и я буду делать это одним нажатием кнопки на панели навигации.
Моя проблема в том, что всякий раз, когда я вызываю метод setText текстового вида, он перескакивает в конец текста. Я пробовал использовать contentOffset и сбросить выбранный Range, но он не работает! Вот мой пример:
// 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: delegate, но он все еще не прокручивается до исходного местоположения.
- (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;
}
Ответы
Ответ 1
Если вы используете 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
Теперь он должен работать (больше не прыгать)
Отношения
Меир Ассаяг
Ответ 2
Основываясь на предложении Meir, здесь код, который программно удаляет выбор (да, я знаю, есть кнопка меню выбора, которая тоже делает это, но я делаю что-то немного фанки) без прокрутки текстового представления.
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;
Ответ 3
Это решение работает для iOS 8:
let offset = textView.contentOffset
textView.text = newText
textView.layoutIfNeeded()
textView.setContentOffset(offset, animated: false)
Нужно называть точно setContentOffset:animated:
, потому что только это отменит анимацию. textView.contentOffset = offset
не отменяет анимацию и не поможет.
Ответ 4
Следующие два решения не работают для меня на iOS 8.0.
textView.scrollEnabled = NO;
[textView.setText: text];
textView.scrollEnabled = YES;
и
CGPoint offset = textView.contentOffset;
[textView.setText: text];
[textView setContentOffset:offset];
Я настраиваю делегата для текстового просмотра для отслеживания события прокрутки и замечаю, что после моей операции для восстановления смещения смещение reset равно 0. Поэтому я вместо этого использую основную очередь операций, чтобы убедиться, что моя операция восстановления происходит после опции "reset to 0".
Здесь мое решение, которое работает для iOS 8.0.
CGPoint offset = self.textView.contentOffset;
self.textView.attributedText = replace;
[[NSOperationQueue mainQueue] addOperationWithBlock: ^{
[self.textView setContentOffset: offset];
}];
Ответ 5
Чтобы отредактировать текст 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];
Удачи.
Ответ 6
Никакие предлагаемые решения не работали для меня. -setContentOffset: анимированный: запускается с помощью -setText: 3 раза с анимированным YES и contentOffset конца (за вычетом поля по умолчанию 8pt UITextView). Я завернул -setText: в guard:
textView.contentOffsetAnimatedCallsDisabled = YES;
textView.text = text;
textView.contentOffsetAnimatedCallsDisabled = NO;
В подклассе UITextView в -setContentOffset: анимированный: put
if (contentOffsetAnimatedCallsDisabled) return; // early return
среди вашей другой логики. Не забудьте супер-вызов. Это работает.
Рафаэль
Ответ 7
в iOS 7. Там швы должны быть ошибкой с sizeThatFits и иметь разрывы строк в вашем UITextView, решение, которое я обнаружил, заключается в том, чтобы обернуть его, отключив прокрутку. Вот так:
textView.scrollEnabled = NO;
CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
textView.scrollEnabled = YES;
и было зафиксировано странное переключение.
Ответ 8
Взгляните на UITextViewDelegate, я считаю, что метод textViewDidChangeSelection может позволить вам делать то, что вам нужно.
Ответ 9
Старый вопрос, но у меня была такая же проблема с приложением 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];
});
Ответ 10
Я столкнулся с аналогичной, если не той же проблемой в IOS9. Изменение характеристик какого-либо текста, скажем, BOLD, вызвало просмотр прокрутки выделения из поля зрения. Я отсортировал это, добавив вызов scrollRangeToVisible после setSelectedRange:
[self setSelectedRange:range];
[self scrollRangeToVisible:range];
Ответ 11
Наконец, попробуйте это, проверено на iOS 10
let offset = textView.contentOffset
textView.attributedText = newValue
OperationQueue.main.addOperation {
self.textView.setContentOffset(offset, animated: false)
}
Ответ 12
Не так изящное решение, но оно работает так, чтобы заботиться:
- (IBAction)changeTextProgrammaticaly{
myTextView.text = @"Some text";
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(rewindOffset) userInfo:nil repeats:NO];
}
- (void)rewindOffset{
[myTextView setContentOffset:CGPointMake(0,0) animated: NO];
}
Ответ 13
Я нашел решение, которое надежно работает в iOS 6 и 7 (и, возможно, более ранних версиях). В подклассе UITextView выполните следующие действия:
@interface MyTextView ()
@property (nonatomic) BOOL needToResetScrollPosition;
@end
@implementation MyTextView
- (void)setText:(NSString *)text
{
[super setText:text];
self.needToResetScrollPosition = YES;
}
- (void)layoutSubviews
{
[super layoutSubviews];
if (self.needToResetScrollPosition) {
self.contentOffset = CGPointMake(0, 0);
self.needToResetScrollPosition = NO;
}
}
Ни один из других ответов не работает в iOS 7, потому что он будет корректировать смещения прокрутки во время отображения.