使用 drawGlyphsForGlyphRange 绘制外部内容插图

Drawing outside content insets with drawGlyphsForGlyphRange

我正在尝试根据文本属性在 NSTextView 中的行旁边显示一些额外的符号。

我已成功子类化 NSLayoutManager,但布局管理器似乎无法在 textContainerInset 设置的区域之外绘制。

因为我的文本视图可能有很长的字符串,所以我希望保持绘图与显示字形的连接。有没有办法欺骗布局管理器能够在内容插图内绘制——或者我是否使用另一种方法来代替 drawGlyphsForGlyphRange?

我试过在绘图前后调用 super,以及存储和不存储图形状态。我也尝试 setDrawsOutsideLineFragment:YES 的字形,但没有运气。

像 Xcode 编辑器本身使用更改标记,所以我知道这在某种程度上是可行的,但很可能我从错误的地方看。

我的画法,简化:

- (void)drawGlyphsForGlyphRange:(NSRange)glyphsToShow atPoint:(NSPoint)origin {
    [super drawGlyphsForGlyphRange:glyphsToShow atPoint:origin];
    
    NSTextStorage *textStorage = self.textStorage;
    NSTextContainer *textContainer = self.textContainers[0];
    
    NSRange glyphRange = glyphsToShow;
    NSSize offset = self.textContainers.firstObject.textView.textContainerInset;
        
    while (glyphRange.length > 0) {
        NSRange charRange = [self characterRangeForGlyphRange:glyphRange actualGlyphRange:NULL], attributeCharRange, attributeGlyphRange;
        
        id attribute = [textStorage attribute:@"Revision" atIndex:charRange.location longestEffectiveRange:&attributeCharRange inRange:charRange];
        attributeGlyphRange = [self glyphRangeForCharacterRange:attributeCharRange actualCharacterRange:NULL];
        attributeGlyphRange = NSIntersectionRange(attributeGlyphRange, glyphRange);

        if (attribute != nil) {
            [NSGraphicsContext saveGraphicsState];
            
            NSRect boundingRect = [self boundingRectForGlyphRange:attributeGlyphRange
                                                  inTextContainer:textContainer];
            
            // Find the top of the revision
            NSPoint point = NSMakePoint(offset.width - 20, offset.height + boundingRect.origin.y + 1.0);
            
            NSString *marker = @"*";
            
            [marker drawAtPoint:point withAttributes:@{
                NSForegroundColorAttributeName: NSColor.blackColor;
            }];
                                   
            [NSGraphicsContext restoreGraphicsState];
        }
                
        glyphRange.length = NSMaxRange(glyphRange) - NSMaxRange(attributeGlyphRange);
        glyphRange.location = NSMaxRange(attributeGlyphRange);
    }
}

答案比我预想的要简单得多。

您可以为关联的 NSTextContainer 设置 lineFragmentPadding,以便为在边距中绘制留出更多空间。在为文本容器设置插图时必须考虑到这一点。