2016-03-25 36 views
5

Guardando la documentazione per NSLayoutManager, in particolare il metodo drawUnderlineForGlyphRange:underlineType:baselineOffset:lineFragmentRect:lineFragmentGlyphRange:containerOrigin:, ho notato quanto segue (sottolineatura mia):Come definire un costume NSUnderlineStyle

underlineVal
Lo stile di sottolineatura da disegnare. Questo valore è una maschera derivata dal valore per NSUnderlineStyleAttributeName, ad esempio, (NSUnderlinePatternDash | NSUnderlineStyleThick). Le sottoclassi possono definire stili di sottolineatura personalizzati.

La mia domanda è: come è esattamente ciò che si intende fare?

NSUnderlineStyle è un enum, che non è possibile estendere o sovrascrivere. Ovviamente si può fornire un valore casuale grezzo Int per l'attributo, non coperta dai casi enum:

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

che fornirà un "non valido" ma utilizzabile underlineType al layout Manger:

debugger screenshot

Ma questo sembra poco sicuro ed è decisamente poco elegante.

Non sono stato in grado di trovare alcun esempio online o ulteriori indizi nella documentazione Apple su come appaiono questi mitici tipi di stile di sottolineatura personalizzati. Mi piacerebbe sapere se mi manca qualcosa di ovvio.

+0

NSUnderlineStyle sembra essere un povero t giocatore di eam. È scarsamente documentato e, in Swift, non è stato ancora convertito in set di opzioni. Quando si leggono le bandiere in uno stile dato, sembra inaffidabile (oppure sto facendo qualcosa di sbagliato). Vorrei poterti aiutare di più, ma sto ancora indagando su una soluzione ... –

risposta

3

Ho un progetto di esempio qui che ho usato per un discorso sulla TextKit che ho dato un po 'indietro che fa esattamente quello che stai cercando: https://github.com/dtweston/text-kit-example

La sottolineatura in questo caso è una linea ondulata:

underline screenshot

la carne della soluzione è un NSLayoutManager personalizzato:

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) 
     } 
    } 
}