У меня есть 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;
}
Я сделал что-то подобное, и прокрутка выполняется на следующей итерации runloop, например '[self performSelector: @selector (scrollProgressTextViewToEnd) withObject: nil afterDelay: 0];'. – Willeke
@ Виллеке сначала идет, кажется, работает! Идти в этот день, но помните, что в качестве ответа я могу дать вам кредит? –
Так что, попробовав это в течение нескольких часов, он по-прежнему, кажется, иногда не прокручивается. =/ –