代码之家  ›  专栏  ›  技术社区  ›  Lyndsey Ferguson

当水平调整包含nstextview的大小时,如何停止nsscrollview从滚动到顶部?

  •  2
  • Lyndsey Ferguson  · 技术社区  · 15 年前

    我有一个nstextview,我想显示一个水平滚动条。除了垂直滚动条有问题外,在互联网上跟踪一些线索后,大部分信息都能正常工作。

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

    完成这项工作后,我注意到我的nsscrollview会在键入时显示和隐藏垂直滚动条。我已经通过在调整大小之前将autohidescrolls设置为no,然后将其设置为yes来“修复”这个问题。但是,在我键入垂直滚动条时仍然存在另一个问题 拇指 跳到滚动条的顶部,然后在键入时返回到正确的位置。我键入“a”<space>,它跳到顶部,我再次按<space>,它跳回到正确的位置。

    有什么想法吗?

    以下是一些示例代码:

    - (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];
            }
        }   
    }
    
    1 回复  |  直到 15 年前
        1
  •  2
  •   Lyndsey Ferguson    15 年前

    多亏了罗斯·卡特 post Cocoa-Dev list ,我解决了这个问题。

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