NSLayoutManager boundingRectForGlyphRange off por alguns pontos

Quero "destacar" palavras específicas no UITextView, não com uma cor sólida (o que seria possível viaNSAttributedString), mas com um gradiente e talvez alguns outros efeitos especiais.

Por isso, decidi que seria necessário criar manualmente uma vista e sobrepor (ou sobrepor) usando os retângulos delimitadores do texto fornecido.

Para minha surpresa, isso acabou sendo bastante direto. O exemplo está dentro de um UIViewController,txtView Começar umUITextView conectado comoIBOutlet:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    // Converting to NSString as I need a NSRange for glphyRangeForCharacterRange
    // (a normal String in Swift returns a Range)
    let charRange = (txtView.text as NSString).rangeOfString("dolor sit er elit")
    assert(charRange.location != NSNotFound, "Character Range could not be found.")

    let glyphRange = txtView.layoutManager.glyphRangeForCharacterRange(charRange,
        actualCharacterRange: nil)
    let glyphContainer = txtView.layoutManager.textContainerForGlyphAtIndex(glyphRange.location, effectiveRange: nil)
    let glyphRect = txtView.layoutManager.boundingRectForGlyphRange(glyphRange,
        inTextContainer: glyphContainer!)

    let highlightView = UIView(frame: glyphRect)
    highlightView.alpha = 0.3
    highlightView.backgroundColor = UIColor.redColor()
    txtView.addSubview(highlightView)
}

Infelizmente, isso leva à exibição overlain (em vermelho na captura de tela abaixo), diminuindo alguns pontos.

Sempre parece estar na mesma quantidade. O que significaria que eu provavelmente poderia codificar, mas isso nunca foi uma boa ideia. Testei isso no Simulator com vários dispositivos e em um iPhone 6 com iOS 8.1.3.

Também tentei outras variações (criando meu próprio NSTextContainer etc.), inspiradas ema pergunta sobre como obter um CGRect para uma substring e"boundingRectForGlyphRange nem sempre funciona para todas as strings"

Alguma idéia (além derecorrendo ao CoreText)?

questionAnswers(1)

yourAnswerToTheQuestion