2016-09-20 4 views
0

У меня есть NSTextView, который отображает то, что я бы назвал «скользящим журналом». Новые AttributedString добавляются примерно каждую секунду. То, что я хотел бы сделать, - обрезать с начала NSTextView, если строка достигла определенной длины или определенного количества строк. Это значит, что отображаемый лог не занимает тонны памяти.Предельная длина текста автопрокрутки NSTextView

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

Ожидаемое поведение:

  • Снимите ведущие линии в случае необходимости (я на самом деле не волнует, если это строки или количество символов, в зависимости от того легче).
  • Автопрокрутка вниз, если просмотр не прокручивается (так что если пользователь в настоящее время прокручивается, они не автопрокручиваются снизу).

Код:

- (void)append:(TextTag*)text toTextView:(MyNSTextView *) textView { 

    dispatch_async(dispatch_get_main_queue(), ^{ 

     NSAttributedString *attr = [self stringFromTag:text]; 

     NSScroller *scroller = [[textView enclosingScrollView] verticalScroller]; 

     double autoScrollToleranceLineCount = 3.0; 

     NSUInteger lines = [self countLines:[textView string]]; 
     double scrolled = [scroller doubleValue]; 
     double scrollDiff = 1.0 - scrolled; 
     double percentScrolled = autoScrollToleranceLineCount/lines; 

     BOOL shouldScrollToBottom = scrollDiff <= percentScrolled; 

     [textView.textStorage beginEditing]; 

     if (lines >= 10000) { 
      NSRange removeRange = [self getRemovalRange:textView.string]; 
      [textView.textStorage deleteCharactersInRange:removeRange]; 
     } 

     [[textView textStorage] appendAttributedString:attr]; 

     [textView.textStorage endEditing]; 

     if(shouldScrollToBottom) { 
      [textView scrollRangeToVisible:NSMakeRange([[textView string] length], 0)]; 
     } 
    }); 
} 

- (NSRange)getRemovalRange:(NSString *)s { 

    NSUInteger numberOfLines, index, stringLength = [s length]; 

    for (index = 0, numberOfLines = 0; index < stringLength; 
     numberOfLines++) { 
     index = NSMaxRange([s lineRangeForRange:NSMakeRange(index, 0)]); 
     if (numberOfLines >= 100) { 
      break; 
     } 
    } 

    return NSMakeRange(0, index); 
} 

- (NSUInteger) countLines:(NSString *)s { 

    NSUInteger numberOfLines, index, stringLength = [s length]; 

    for (index = 0, numberOfLines = 0; index < stringLength; 
     numberOfLines++) { 
     index = NSMaxRange([s lineRangeForRange:NSMakeRange(index, 0)]); 
    } 
    return numberOfLines; 
} 
+0

Я сделал что-то подобное, и прокрутка выполняется на следующей итерации runloop, например '[self performSelector: @selector (scrollProgressTextViewToEnd) withObject: nil afterDelay: 0];'. – Willeke

+0

@ Виллеке сначала идет, кажется, работает! Идти в этот день, но помните, что в качестве ответа я могу дать вам кредит? –

+0

Так что, попробовав это в течение нескольких часов, он по-прежнему, кажется, иногда не прокручивается. =/ –

ответ

0

Вот что я сделал (лет назад, методом проб и ошибок).

- (void)scrollProgressTextViewToEnd 
{ 
    if ([progressTextView isFlipped]) 
     [progressTextView scrollPoint:NSMakePoint(0.0, NSMaxY([progressTextView frame]) - NSHeight([progressTextView visibleRect]))]; 
    else 
     [progressTextView scrollPoint:NSMakePoint(0.0, 0.0)]; 
} 

- (void)appendToProgressText:(NSString *)theString bold:(BOOL)theBold 
{ 
    [progressTextView.textStorage beginEditing]; 
    [self appendToProgressText:theString bold:theBold]; 
    [progressTextView.textStorage endEditing]; 
    [progressTextView didChangeText]; 
    [self performSelector:@selector(scrollProgressTextViewToEnd) withObject:nil afterDelay:0]; 
} 

Метод appendToProgressText добавляет theString к progressTextView.textStorage и не использует progressTextView.

Смежные вопросы