在NSLayoutManager中控制自定义文本属性周围的间距 [英] Control spacing around custom text attributes in NSLayoutManager

查看:612
本文介绍了在NSLayoutManager中控制自定义文本属性周围的间距的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I’ve got a custom NSLayoutManager subclass I’m using to draw pill-shaped tokens. I draw these tokens for substrings with a custom attribute (TokenAttribute). I can draw no problem.

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

However, I need to add a little bit of "padding" around the ranges with my TokenAttribute (so that the round rectangle background of the token won’t intersect with the text).

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

In the above image, I’m drawing my token’s background with an orange colour, but I want extra padding around 469 so the background isn’t right up against the text.

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

I’m not really sure how to do this. I tried overriding -boundingRectForGlyphRange:inTextContainer: to return a bounding rect with more horizontal padding, but it appears the layout of glyphs isn’t actually affected by this.

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

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

Here’s the code I use to draw the background, in my layout manager subclass:

- (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);
    }
}

推荐答案

NSLayoutManagerDelegate中定义了一些方法,这些方法用作基于字形的自定义点.

There are methods defined in NSLayoutManagerDelegate, that serve as glyph-based customisation points.

使用

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 来标记它们. 然后将更改后的数组传递给

to identify the glyphs associated with the whitespace surrounding your range-of-interest and mark those by altering their value in the props array to NSLayoutManager.GlyphProperty.controlCharacter. Then pass this altered array to

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

之后,您可以实施

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

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

to again identify the glyphs of interest and return the predefined action:

NSLayoutManager.ControlCharacterAction.whitespace

最后,这使您可以实现

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

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

to alter the bounding box used for the glyphs. Simply return the appropriated dimensions. This will have effect on the following layout-mechanism.

祝你好运!

这篇关于在NSLayoutManager中控制自定义文本属性周围的间距的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆