Search code examples
swiftmacosnslayoutmanager

Calculating Text Height as per Apple Documentation


I followed this to try and determine the height of a container I would need before placing text in a CATextLayer. However, I am not getting the expected results. The returned NSRect is (0.0, 0.0, 0.0, 0.0). What am I doing wrong?

func heightForStringDrawing(myString: NSString, myFont: NSFont, myWidth: CGFloat) -> NSRect {
    
    let textStorage:NSTextStorage = NSTextStorage.init(string: myString as String)
    let textContainer:NSTextContainer = NSTextContainer.init(containerSize: NSMakeSize(myWidth, CGFloat.infinity))
    let layoutManager:NSLayoutManager = NSLayoutManager()
    layoutManager.addTextContainer(textContainer)
    layoutManager.glyphRange(for: textContainer)
    textStorage.addLayoutManager(layoutManager)
    textStorage.addAttributes([NSAttributedString.Key.font : myFont], range: NSMakeRange(0, textStorage.length))
    textContainer.lineFragmentPadding = 0.0

    return layoutManager.usedRect(for: textContainer)
}

And I am calling it like this:

print(myLayers.heightForStringDrawing(myString: "Some really, really, really, very long text.", myFont: NSFont.systemFont(ofSize: 14), myWidth: 66))

This results in a returned NSRect as (0.0, 0.0, 0.0, 0.0), but I expect (0.0, 0.0, 66.0, (a number larger than 0.0 or 14.0)). It's not even returning the width.

If I send an empty myString = "" I get a returned NSRect of (0.0, 0.0, 0.0, 14.0). But still no width, as supplied in the call.


Solution

  • So it appears that you simply didn't translate the code they gave you into Swift correctly. Translate the code they give you in the order they give it to you, like this:

    func heightForStringDrawing(myString:String, myFont:NSFont, myWidth: GFloat) -> NSRect {
        let textStorage = NSTextStorage(string: myString)
        let textContainer = NSTextContainer(containerSize: NSMakeSize(myWidth, .greatestFiniteMagnitude))
        let layoutManager = NSLayoutManager()
        layoutManager.addTextContainer(textContainer)
        textStorage.addLayoutManager(layoutManager)
        textStorage.addAttributes([.font : myFont], range: NSMakeRange(0, textStorage.length))
        textContainer.lineFragmentPadding = 0.0
        layoutManager.glyphRange(for: textContainer) // <- here
        return layoutManager.usedRect(for: textContainer)
    }