Proper way to customize layout fragments' frames?

I found that compared with TextKit 1, NSTextLayoutManager does not provide any opportunity to customize line rectangles. In particular, I cannot do much about the frame of a NSTextLayoutFragment. I am curious about the proper approach to:

  1. limit the width and horizontal offset of a paragraph;

  2. add spacing below and above a paragraph;

  3. enclose a paragraph along an arbitrary path.

For the first question, I noticed that in the sample app, when layout comments, BubbleLayoutFragment does not change the positions of any characters. While it did override renderingSurfaceBounds, it merely expands the bounds, without moving its text contents. And there seems to be no way to do so.

For the second question, I noticed that paragraphSpacing and paragraphSpacingBefore set on the paragraph style seems to have no effect. According to the video, all layout fragments are stacked like a list. Therefore, this is an intended feature, right?

Right now, my solutions to the first two questions are:

  • If I want to control the horizontal position of a paragraph, I could simply set headIndent and trailIndent on the paragraph style.
  • If I want to add spacing above or below a paragraph, I can add empty lines and set minimalLineHeight for the newline character.

Are those the recommended ways to achieve such effect?


Personally, I am not very interested in the third feature, enclosing a paragraph along an arbitrary path. However, I am indeed curious about how to add paragraph-level attachment, such as an block image/custom view between paragraphs. I think what I could do is:

  1. add an empty new line and set its height to leave enough space for the custom view;

  2. configure a CALayer or even a view and put it where the new line should be;

If I want to layout characters within a strange shape, I could compute the shape's height based on the width, using TextKit 1, and then insert the new line as in step 1.

Is this the intended way to approach such situation?

I have the same issue about the paragraph spacing for the fragments. It looks like the NSParagraphStyle does not works for TextKit 2.

Finally, I use a new subclass for NSTextLayoutFragment and override the bottomMargin to the spacing.

extension TextAreaView: NSTextLayoutManagerDelegate {

    func textLayoutManager(_ textLayoutManager: NSTextLayoutManager, textLayoutFragmentFor location: NSTextLocation, in textElement: NSTextElement) -> NSTextLayoutFragment {

        let endTextLocation = textLayoutManager.documentRange.endLocation

        if let elementRangeEndLocation = textElement.elementRange?.endLocation,

           elementRangeEndLocation.compare(endTextLocation) == .orderedSame {

            return NSTextLayoutFragment(textElement: textElement, range: textElement.elementRange)

        } else {

            return ParagraphTextLayoutFragment(textElement: textElement, range: textElement.elementRange)

        }

    }

}

Maybe we could add some view during surfacing drawing due to the NSTextLayoutFragment could be customized by subclassing. I'm working on adding a custom view inline. And still needs some efforts.

I have a similar question that when layout, some attributes of NSAttributedString make no effect and some others make effects not expected, so how to deal with them?

In my app, I need to increase the line space in paragraphs. Therefore, I set the paragraphStyle like this

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .justified
paragraphStyle.lineHeightMultiple = 1.6
paragraphStyle.paragraphSpacing = defaultFontSize * 2.0
paragraphStyle.hyphenationFactor = 1
         
for range in allMyRanges {
  attributedString.removeAttribute(NSAttributedString.Key.paragraphStyle, range: range)
  attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: range)
}

When layout, all paragraphs with this paragraphStyle had the wrong frames and were also half covered by the paragraphs following them, like this:

Is there a way to control the frame of layoutFragments?

Proper way to customize layout fragments' frames?
 
 
Q