I would like to render a divider line in a NSTextView (like the <div> HTML item) on macOS 10.13 or later. I use Objective-C.
I've searched for solutions and it looks like the recommended solution is to use a NSTextAttachmentCell. There was supposedly an example provided on the cocoa-dev mailing list but the archives for this useful mailing list are gone.
The issue I'm observing with the NSTextAttachmentCell solution is that it is working almost well with a simple NSTextView example but when used in a more complex application, the rendering of the divider is still fine but there's a huge vertical gap between the divider and the text below the divider.
The online documentation for the NSTextAttachmentCell class is not really helpful (and contains typos: "With the exceptions of cellBaselineOffset, attachment, and attachment, all of these methods are implemented by the NSCell class.For general information on text attachments, " -> "attachment" twice, no space between "class." and "For general").
Here's the simple code I'm currently testing for the attachment cell:
@implementationMyDividerTextAttachmentCell
- (NSRect)cellFrameForTextContainer:(NSTextContainer *)textContainer proposedLineFragment:(NSRect)lineFrag glyphPosition:(NSPoint)position characterIndex:(NSUInteger)charIndex
{
return NSMakeRect(lineFrag.origin.x, lineFrag.origin.y, textContainer.size.width, 10);
}
- (void)drawWithFrame:(NSRect)cellFrame inView:(nullable NSView *)controlView
{
[[NSColor darkGrayColor] setStroke];
[NSBezierPath strokeLineFromPoint:NSMakePoint(0, NSMidY(cellFrame)) toPoint:NSMakePoint(NSMaxX(cellFrame), NSMidY(cellFrame))];
}
[Q] Is there an obvious reason why there would be a huge gap (think 200 pixels/points) below the divider? What is the recommended way to render a divider line in a NSTextView if it's not NSTextAttachmentCell.
Creating your own NSTextAttachment subclass and implementing the NSTextAttachmentContainer methods will be a better choice, because that is a more "modern" way than using NSTextAttachmentCell, given that your target platform is macOS 10.13+ (and so TextKit 2 is not a choice).
If you need to stick to NSTextAttachmentCell, yeah, try return NSMakeRect(0, 0, lineFrag.size.width, 10); in cellFrameForTextContainer:.... The method doesn't expect a frame in the text container's coordinate system; it expects the attachment bounds relative to the glyph's baseline position (i.e., origin is usually (0, 0) or (0, baselineOffset)). The documentation is indeed confusing.
Also, in drawWithFrame:inView:, try to draw from NSMinX(cellFrame) instead of 0 so it respects container padding.
Best,
——
Ziqiao Chen
Worldwide Developer Relations.