限制自动滚动NSTextView的文本长度

时间:2016-09-20 23:53:06

标签: objective-c nstextview

我有一个显示我称之为“滚动日志”的NSTextView。新的AttributedString几乎每秒都会被添加。我想做的是,如果字符串达到一定长度或一定数量的行,则从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;
}

1 个答案:

答案 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];
}

方法appendToProgressTexttheString添加到progressTextView.textStorage,但不使用progressTextView