Подтвердить что ты не робот

Остановить 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;
}
4b9b3361

Ответ 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, потому что он будет корректировать смещения прокрутки во время отображения.