I have a problem with CATextlayer. I set wrapped == YES for CATextlayer and it auto set multi line for this. But the line spacing is very small and look it verry bad. Is there any way to set line spacing for CATextlayer? Thanks.
4 Answers
I think CATextLayer
is only intended for lightweight uses. You can set its string
property to an NSAttributedString
to alter some attributes like font and size but many others are ignored, including line height and spacing.
For finer control over how text in a layer is rendered you can use a regular CALayer
and NSAttributedString
’s drawing methods; for example:
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:ctx flipped:YES]];
[self.someAttributedString drawInRect:layer.bounds];
[NSGraphicsContext restoreGraphicsState];
}

- 549
- 6
- 10
Like @spinacher I noticed that CATextLayer
ignores paragraph styles like line spacing. I solved this by subclassing CALayer and draw the attributed string more directly. Much of the code is copied from this article
class CAAttributedTextLayer: CALayer {
public var attrString = NSAttributedString(string: "")
override func draw(in ctx: CGContext) {
// Flip the coordinate system
ctx.textMatrix = .identity
ctx.translateBy(x: 0, y: bounds.size.height)
ctx.scaleBy(x: 1.0, y: -1.0)
let path = CGMutablePath()
path.addRect(bounds)
let framesetter = CTFramesetterCreateWithAttributedString(attrString as CFAttributedString)
let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, attrString.length), path, nil)
CTFrameDraw(frame, ctx)
}
}

- 368
- 1
- 12
-
how to use above code? can you please give any code example to use – Hardik Thakkar Dec 15 '21 at 06:54
-
@HardikThakkar Just add the class to your code, and replace your CATextLayer with CAAttributedTextLayer. Then set the attrString property to an attributed string – torof Dec 16 '21 at 12:50
CATextLayer
lineheight depends on your fonts native height of 1 unit
usually expressed with a typographical unit-type named "Geviert".
If you are able to edit your font - you are also able to set the lineheight of course. Because the unit size of one signets maximum unit size is used when Quartz will interpret/render your font.
sorry the screenshot in german, of a font-editing with setting for a font that will have only 6 pixel height and a linespacing of two pixels. Even in font creation software it is not obvious to read out the line height as you can see. Nowhere is 2 pixels given as linespace.. instead the unit-size Geviert is given here.
So yes there is no other way that CATextLayer could print other lineheights in a native way. You will always have to use a workaround by reading out the "\n"
of your NSString and re-allocate another CATextLayer for the next line or going with other Classes to print text on screen like the example from torof with a CAAttributedTextLayer
that can express NSAttributedString
s
Lineheight for Quartz Rendering is a relative size depending on the Font.
Some fonts need more linespace because they are heavy in circles and underscore graphics. If this relative lineheight would not exist, you would have to give a lineheight on every text printing instead using the standard 1 unit * Geviert size + size below any sign
(screenshot "Unterlänge")
When you can edit your font file and set the mentioned Geviert
size to a value you wish than CATextLayer
will always render in perfect line height. Which is very handy when you create image buffers for LCD or other low pixel displays.

- 3,163
- 2
- 21
- 30
You can refer following tutorial :
-
This doesn't answer the question at all. The question is about changing the line spacing of a `CATextLayer`, not about calculating the height for a specific width... – IluTov May 01 '14 at 17:01