How to replace a text attachment with a custom dra

2020-03-24 08:42发布

问题:

My ultimate goal is to give the user the ability to split a text inside an NSTextView or UITextView into several sections, where two subsequent sections are visually separated by a custom view separator (possibly, but not necessarily a horizontal rule – I want to be able to adjust the visual appearance of the separator without a hassle).

I need a solution that works on both platforms: macOS and iOS.

(My related question focused on a solution for macOS and there is one that makes use of NSTextAttachmentCells which are not available on iOS.)

My current approach to tackling this problem is the following:

  1. I have a button in the window's toolbar to insert a section break.
  2. When the user taps that button, I create a new attributed string with no text but with a text attachment:

    let attachment = SectionChangeTextAttachment()
    let attachmentString = NSAttributedString(attachment: attachment)
    

    (SectionChangeTextAttachment is a custom subclass of NSTextAttachment that I created in order to be able to distinguish this section break attachment from other possible attachments.)

  3. I insert that attachmentString to text storage at the current cursor position:

    textStorage.insert(attachmentString, at: textView.selectedRange().location)
    
  4. I create a custom NSLayoutManager subclass. Its task is to find all the attachments of class SectionChangeTextAttachment and replace all occurrences with a separator drawing (or glyph?). And here's the problem: With Apple's limited and partially outdated documentation, I cannot figure out how to do this.

So my question is:

How can I make my layout manager replace attachment characters (with a specific attachment) with a custom drawing (of a separator) that takes up more space than the character / glyph?

(I guess there is no glyph for the attachment character and thus the layout manager doesn't provide any space for it.)

Which methods do I need to override in order to make this work?

(Does this approach even make sense to begin with?)