How to define a custom NSUnderlineStyle

Looking at the documentation for NSLayoutManager , in particular, the drawUnderlineForGlyphRange: underlineType: baselineOffset: lineFragmentRect: lineFragmentGlyphRange: containerOrigin: method, I noticed the following (main focus):

underlineVal
Underline style for drawing. This value is the mask obtained from the value for NSUnderlineStyleAttributeName - for example, ( NSUnderlinePatternDash | NSUnderlineStyleThick ). Subclasses can define custom underline styles .

My question is: how exactly should this be done?

NSUnderlineStyle is an enumeration that you cannot extend or override. Of course, you can provide a random raw Int value for the attribute not covered by the enumeration cases:

self.addAttribute(NSUnderlineStyleAttributeName, value: 100022, range: lastUpdatedWordRange)

Which will deliver an "Invalid" but useful underlineType for the Layout Wizard:

debugger screen shot

But it hardly looks safe and certainly inelegant.

I was not able to find examples online or further clues in Apple's documentation on how these mythical custom underline types look. I would really like to know if I am missing something obvious.

+5
source share
1 answer

I have an example project that I used to talk in TextKit, which I gave some time ago, which does exactly what you are looking for: https://github.com/dtweston/text-kit-example

We emphasize in this case the short line:

underline screenshot

The soft solution is the custom NSLayoutManager:

 let CustomUnderlineStyle = 0x11 class UnderlineLayoutManager: NSLayoutManager { func drawFancyUnderlineForRect(_ rect: CGRect) { let left = rect.minX let bottom = rect.maxY let width = rect.width let path = UIBezierPath() path.move(to: CGPoint(x: left, y: bottom)) var x = left var y = bottom var i = 0 while (x <= left + width) { path.addLine(to: CGPoint(x: x, y: y)) x += 2 if i % 2 == 0 { y = bottom + 2.0 } else { y = bottom } i += 1; } path.stroke() } override func drawUnderline(forGlyphRange glyphRange: NSRange, underlineType underlineVal: NSUnderlineStyle, baselineOffset: CGFloat, lineFragmentRect lineRect: CGRect, lineFragmentGlyphRange lineGlyphRange: NSRange, containerOrigin: CGPoint) { if underlineVal.rawValue & CustomUnderlineStyle == CustomUnderlineStyle { let charRange = characterRange(forGlyphRange: glyphRange, actualGlyphRange: nil) if let underlineColor = textStorage?.attribute(NSUnderlineColorAttributeName, at: charRange.location, effectiveRange: nil) as? UIColor { underlineColor.setStroke() } if let container = textContainer(forGlyphAt: glyphRange.location, effectiveRange: nil) { let boundingRect = self.boundingRect(forGlyphRange: glyphRange, in: container) let offsetRect = boundingRect.offsetBy(dx: containerOrigin.x, dy: containerOrigin.y) drawFancyUnderlineForRect(offsetRect) } } else { super.drawUnderline(forGlyphRange: glyphRange, underlineType: underlineVal, baselineOffset: baselineOffset, lineFragmentRect: lineRect, lineFragmentGlyphRange: lineGlyphRange, containerOrigin: containerOrigin) } } } 
+3
source

Source: https://habr.com/ru/post/1245765/


All Articles