【问题标题】:How to stop NSScrollView from scrolling to top when horizontally resizing contained NSTextView?水平调整包含 NSTextView 的大小时,如何阻止 NSScrollView 滚动到顶部?
【发布时间】:2009-11-16 21:23:38
【问题描述】:

我有一个要显示水平滚动条的 NSTextView。按照互联网上的一些线索,我大部分都可以工作,除了垂直滚动条有问题。

我所做的是找到最长线的宽度(以给定字体的像素为单位),然后适当地调整 NSTextContainer 和 NSTextView 的大小。这样水平滚动条代表宽度,向右滚动将滚动到最长文本行的末尾。

完成这项工作后,我注意到我的 NSScrollView 会在我键入时显示和隐藏垂直滚动条。我通过在调整大小之前将 autohidesScrollers 设置为 NO 并在之后设置为 YES 来“解决”这个问题。但是,仍然存在另一个问题,当我键入时,垂直滚动条 thumb 会跳到滚动条的顶部,然后在我键入时返回到正确的位置。我输入'a' ,它会跳到顶部,我再次按,它会跳回正确的位置。

有什么想法吗?

这里是一些示例代码:

- (CGFloat)longestLineOfText
{
    CGFloat longestLineOfText = 0.0;

    NSRange lineRange;

    NSString* theScriptText = [myTextView string];

    NSDictionary* attributesDict = [NSDictionary dictionaryWithObject:scriptFont forKey:NSFontAttributeName]; //scriptFont is a instance variable

    NSUInteger characterIndex = 0;
    NSUInteger stringLength = [theScriptText length];

    while (characterIndex < stringLength) {
        lineRange = [theScriptText lineRangeForRange:NSMakeRange(characterIndex, 0)];

        NSSize lineSize = [[theScriptText substringWithRange:lineRange] sizeWithAttributes:attributesDict];
        longestLineOfText = max(longestLineOfText, lineSize.width);

        characterIndex = NSMaxRange(lineRange);
    }

    return longestLineOfText;

}

// ----------------------------------------------------------------------------

- (void)updateMyTextViewWidth
{
    static CGFloat previousLongestLineOfText = 0.0;

    CGFloat currentLongestLineOfText = [self longestLineOfText];
    if (currentLongestLineOfText != previousLongestLineOfText) {
        BOOL shouldStopBlinkingScrollBar = (previousLongestLineOfText < currentLongestLineOfText);
        previousLongestLineOfText = currentLongestLineOfText;

        NSTextContainer* container = [myTextView textContainer];
        NSScrollView* scrollView = [myTextView enclosingScrollView];
        if (shouldStopBlinkingScrollBar) {
            [scrollView setAutohidesScrollers:NO];
        }

        CGFloat padding = [container lineFragmentPadding];

        NSSize size = [container containerSize];
        size.width = currentLongestLineOfText + padding * 2;
        [container setContainerSize:size];

        NSRect frame = [myTextView frame];
        frame.size.width = currentLongestLineOfText + padding * 2;
        [myTextView setFrame:frame];

        if (shouldStopBlinkingScrollBar) {
            [scrollView setAutohidesScrollers:YES];
        }
    }   
}

【问题讨论】:

    标签: cocoa macos nstextview nsscrollview


    【解决方案1】:

    感谢 Ross Carter 在Cocoa-Dev list 上的post,我解决了这个问题。

    A.您必须设置文本视图以支持水平滚动:

    - (void)awakeFromNib {
        [myTextView setHorizontallyResizable:YES];
        NSSize tcSize = [[myTextView textContainer] containerSize];
        tcSize.width = FLT_MAX;
        [[myTextView textContainer] setContainerSize:tcSize];
        [[myTextView textContainer] setWidthTracksTextView:NO];
    }
    

    B.您必须在文本视图更改时更新它的宽度,否则水平滚动条不会正确更新:

    - (void)textDidChange:(NSNotification *)notification
    {
        [self updateTextViewWidth];
    }
    
    - (CGFloat)longestLineOfText
    {
        CGFloat longestLineOfText = 0.0;
    
        NSLayoutManager* layoutManager = [myTextView layoutManager];
    
        NSRange lineRange;
        NSUInteger glyphIndex = 0;
        NSUInteger glyphCount = [layoutManager numberOfGlyphs];
        while (glyphIndex < glyphCount) {
    
            NSRect lineRect = [layoutManager lineFragmentUsedRectForGlyphAtIndex:glyphIndex
                                                                  effectiveRange:&lineRange
                                                         withoutAdditionalLayout:YES];
    
            longestLineOfText = max(longestLineOfText, lineRect.size.width);
    
            glyphIndex = NSMaxRange(lineRange);
        }
    
        return longestLineOfText;
    
    }
    
    // ----------------------------------------------------------------------------
    
    - (void)updateTextViewWidth
    {
        static CGFloat previousLongestLineOfText = 0.0;
    
        CGFloat currentLongestLineOfText = [self longestLineOfText];
        if (currentLongestLineOfText != previousLongestLineOfText) {
            previousLongestLineOfText = currentLongestLineOfText;
    
            NSTextContainer* container = [myTextView textContainer];
            CGFloat padding = [container lineFragmentPadding];
    
            NSRect frame = [myTextView frame];
            frame.size.width = currentLongestLineOfText + padding * 2;
            [myTextView setFrame:frame];
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-03-23
      • 1970-01-01
      • 2011-08-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多