NSLayoutManager中自定义文本属性周围的控件间距

问题描述 投票:10回答:1

我有一个自定义的NSLayoutManager子类,我正在用它绘制药丸状的标记。我为具有自定义属性(TokenAttribute)的子字符串绘制了这些标记。我没问题。

但是,我需要用TokenAttribute在范围周围添加一些“填充”(以便令牌的圆角矩形背景不会与文本相交。

enter image description here

在上图中,我用橙色绘制令牌的背景,但我想在469周围添加额外的填充,以使背景不紧贴文本。

我不太确定该怎么做。我尝试覆盖-boundingRectForGlyphRange:inTextContainer:以返回具有更多水平填充的边界矩形,但字形的布局实际上并不受此影响。

我如何在某些字形/字形范围内增加间距?


这是我在布局管理器子类中用于绘制背景的代码:

- (void)drawGlyphsForGlyphRange:(NSRange)glyphsToShow atPoint:(CGPoint)origin {

    NSTextStorage *textStorage = self.textStorage;
    NSRange glyphRange = glyphsToShow;

    while (glyphRange.length > 0) {

        NSRange characterRange = [self characterRangeForGlyphRange:glyphRange actualGlyphRange:NULL];
        NSRange attributeCharacterRange;
        NSRange attributeGlyphRange;

        id attribute = [textStorage attribute:LAYScrubbableParameterAttributeName 
                                      atIndex:characterRange.location 
                        longestEffectiveRange:&attributeCharacterRange 
                                      inRange:characterRange];

        attributeGlyphRange = [self glyphRangeForCharacterRange:attributeCharacterRange 
                                           actualCharacterRange:NULL];
        attributeGlyphRange = NSIntersectionRange(attributeGlyphRange, glyphRange);

        if (attribute != nil) {
            CGContextRef context = UIGraphicsGetCurrentContext();
            CGContextSaveGState(context);

            UIColor *backgroundColor = [UIColor orangeColor];
            NSTextContainer *textContainer = self.textContainers[0];
            CGRect boundingRect = [self boundingRectForGlyphRange:attributeGlyphRange inTextContainer:textContainer];

            // Offset this bounding rect by the `origin` passed in above
            // `origin` is the origin of the text container!
            // if we don't do this, then bounding rect is incorrectly placed (too high, in my case).
            boundingRect.origin.x += origin.x;
            boundingRect.origin.y += origin.y;

            [backgroundColor setFill];
            UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:boundingRect cornerRadius:boundingRect.size.height / 2.0];
            [path fill];

            [super drawGlyphsForGlyphRange:attributeGlyphRange atPoint:origin];
            CGContextRestoreGState(context);

        } else {
            [super drawGlyphsForGlyphRange:glyphsToShow atPoint:origin];
        }

        glyphRange.length = NSMaxRange(glyphRange) - NSMaxRange(attributeGlyphRange);
        glyphRange.location = NSMaxRange(attributeGlyphRange);
    }
}
ios cocoa-touch uitextview textkit nslayoutmanager
1个回答
0
投票

[NSLayoutManagerDelegate中定义了一些方法,它们用作基于字形的自定义点。

使用

func layoutManager(_ layoutManager: NSLayoutManager, shouldGenerateGlyphs glyphs: UnsafePointer<CGGlyph>, properties props: UnsafePointer<NSLayoutManager.GlyphProperty>, characterIndexes charIndexes: UnsafePointer<Int>, font aFont: NSFont, forGlyphRange glyphRange: NSRange) -> Int

识别与感兴趣范围周围的空白关联的字形,并通过将它们在props数组中的值更改为NSLayoutManager.GlyphProperty.controlCharacter来标记它们。然后将此更改后的数组传递给

NSLayoutManager.setGlyphs(_:properties:characterIndexes:font:forGlyphRange:)

之后,您可以实施

func layoutManager(_ layoutManager: NSLayoutManager, shouldUse action: NSLayoutManager.ControlCharacterAction, forControlCharacterAt charIndex: Int) -> NSLayoutManager.ControlCharacterAction

再次识别感兴趣的字形并返回预定义的动作:

NSLayoutManager.ControlCharacterAction.whitespace

最后,您可以实现

func layoutManager(_ layoutManager: NSLayoutManager, boundingBoxForControlGlyphAt glyphIndex: Int, for textContainer: NSTextContainer, proposedLineFragment proposedRect: NSRect, glyphPosition: NSPoint, characterIndex charIndex: Int) -> NSRect

更改用于字形的边框。只需返回适当的尺寸。这将影响以下布局机制。

祝你好运!

© www.soinside.com 2019 - 2024. All rights reserved.