2009-05-14 5 views
18

Мне нужно обновить небольшое количество текста в прокручиваемом 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: делегировать метод, но он по-прежнему не прокрутки вверх в исходное местоположение.

- (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

Посмотрите на UITextViewDelegate, я считаю, что метод textViewDidChangeSelection может позволить вам делать то, что вам нужно.

+0

Спасибо за ваш вклад. Что должно произойти в этом методе делегата? Это когда окончательный сброс contentOffset и selectedRange должен иметь место? –

0

Не так элегантно решение- но это работает так, кто заботится:

- (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]; 
} 
+0

(Это решение появилось после того, как все другие предлагаемые нами решения не сработали для меня) – Tiger

+0

Это не заслуживает нисходящего потока. Иногда такие прокрутки должны решаться в цикле выполнения. Я знаю, что могут быть более элегантные решения, но это работает и безвредно. – phatmann

14

Если вы используете 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 

Он должен работать сейчас (нет более прыжки)

С уважением Меир Assayag

+2

Не работает на iOS 8. – Dmitry

2

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

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

В UITextView подклассе в -setContentOffset: анимированное: положить

if (contentOffsetAnimatedCallsDisabled) return; // early return 

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

Рафаэль

+0

Спасибо за предложение, я попробую! –

+1

Это не частный API, вы переопределяете UITextView и реализуете поведение самостоятельно в соответствии с моим примером. Ответ Meir Assayag не работал в моем случае и на iOS 3.2. –

+0

На iOS 7 это не работает, так как метод contentOffset будет вызываться снова во время отображения. Я ищу рабочее решение. – phatmann

8

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

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; 
+0

Это решение (установка scrollEnabled ПОСЛЕ установки выбранного диапазона, а не ранее) исправила проблему «прыгающего текста», возникшую при настройке атрибута attributedText UITextView! Спасибо –

+0

Это мне не помогает. – Dmitry

0

Я нашел решение, которое надежно работает в 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; 
    } 
} 

Ни один из других ответов не работают прошивка 7, так как он будет регулировать смещение прокрутки во время просмотра.

+0

self.contentOffset всегда 0,0 для меня (этот подкласс не влияет на предотвращение прокрутки под iOS 7). – Michael

1

Старый вопрос, но у меня была такая же проблема с приложением 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]; 
}); 
2

в прошивке 7. Там швы быть ошибкой с sizeThatFits и имеющими переносами в вашем UITextView решения, которое я нашел, что работает, чтобы обернуть его отключить скроллинг. Например:

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

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

+0

Большая помощь. Спасибо! – JMarsh

+0

На настройке iOS 8 'textView.scrollEnabled = NO' в' textDidChange: ', кажется, отключает прокрутку навсегда. Однако на этой ОС, похоже, достаточно просто переключить 'scrollEnabled' один раз во время' viewDidLoad', то есть установить его на 'NO' и прямо обратно на' YES' –

4

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

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

и

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

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

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

CGPoint offset = self.textView.contentOffset; 
self.textView.attributedText = replace; 
[[NSOperationQueue mainQueue] addOperationWithBlock: ^{ 
    [self.textView setContentOffset: offset]; 
}]; 
+0

Итак, это исправило мою проблему при тестировании на симуляторе, но не устраняйте проблему при ее запуске на моем устройстве. Это заставляет меня думать, что это все еще состояние гонки. Я рассматриваю только подклассирование uitextview и переопределение метода layoutsubviews, чтобы он не запускался, когда я включил свойство блокировки. – Lobsterman

5

Это решение работает для прошивки 8:

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

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

3

Для того, чтобы отредактировать текст 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]; 

Успехов

1

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

[self setSelectedRange:range]; 
    [self scrollRangeToVisible:range]; 
+0

Работает отлично, без ощутимого прыжка и так просто! Я не знаю, как я пропустил это! – siburb

1

Наконец попробовать это, проверен на прошивке 10

let offset = textView.contentOffset 
textView.attributedText = newValue 
OperationQueue.main.addOperation { 
    self.textView.setContentOffset(offset, animated: false) 
} 
Смежные вопросы