I have a NSLayoutManager, NSTextContainer & NSTextStorage
as properties in a custom NSView
(not a TextView) initialized in awakeFromNib()
as follows:
textStorage = NSTextStorage(attributedString: self.attributedString)
layoutManager = NSLayoutManager()
textContainer = NSTextContainer(containerSize: NSMakeSize(self.frame.size.width, 1))
layoutManager.addTextContainer(textContainer)
textStorage.addLayoutManager(layoutManager)
layoutManager.glyphRangeForTextContainer(textContainer)
The vertical containerSize
of the NSTextContainer
is deliberately set to 1 to see if it has the expected effect of hiding the text being rendered - it does not! It is making NO difference in the rendering of this text in the view - which is the subject of the question!
In drawRect
I include the lines below to draw the text:
let glyphRange = layoutManager.glyphRangeForTextContainer(textContainer)
self.lockFocus()
layoutManager.drawGlyphsForGlyphRange(glyphRange, atPoint: NSMakePoint(0, 0))
self.unlockFocus()
NSTextView
else I feel like I'm going to be in for a world of pain! Irrespective of this, NSLayoutManager always starts drawing its text internally in a flipped co-ordinate system (just like NSTextView
)containerSize.width
property of NSTextContainer
has the following effect: it is binding on a line level for all levels including the first (I know it's obvious but stick with me...)containerSize.height
property of NSTextContainer
has a curve-ball: it will NOT be binding on the first line even if the containing view does not have the room to display it vertically BUT will be binding on subsequent lines*it took me a long time to come to this hypothesis about containerSize.height
because I was only drawing one line! *
NSTextContainer
correct?NSTextContainer
has a containerSize
property. The layout manager is laying out the text within that container. Presumably, the container is what is logically being positioned at (0, 0) in your view, but the text is laying out from its top. So, the container has slack.
You could resize the container based on the rect returned from -[NSLayoutManager usedRectForTextContainer:]
to size it to fit.
Update:
I think code like this in your drawRect()
should work for what you want to achieve:
layoutManager.ensureLayoutForTextContainer(textContainer)
var rect = layoutManager.usedRectForTextContainer(textContainer)
rect.origin.x += 2
rect.origin.y = NSMaxY(self.bounds) - NSHeight(rect) - 4
let glyphRange = layoutManager.glyphRangeForTextContainer(textContainer)
layoutManager.drawGlyphsForGlyphRange(glyphRange, atPoint:rect.origin)