2016-07-27 3 views
3

J'affiche du texte qui peut contenir des emoji en utilisant la méthode drawInRect(rect: CGRect) de NSAttributedString. Comme je veux détecter les robinets sur le texte que j'utilise la méthode suivante pour voir quel personnage a été exploité:NSLayoutManager, boundingRectForGlyphRange et emoji

let textStorage = NSTextStorage(attributedString: attributedString) 
let layoutManager = NSLayoutManager() 
layoutManager.usesFontLeading = true 
textStorage.addLayoutManager(layoutManager) 

let textContainer = NSTextContainer(size: containerSize) 
layoutManager.addTextContainer(textContainer) 

textContainer.lineFragmentPadding = 0.0 

layoutManager.ensureLayoutForTextContainer(textContainer) 

let tappedIndex = layoutManager.characterIndexForPoint(point, 
     inTextContainer: textContainer, 
     fractionOfDistanceBetweenInsertionPoints: nil) 

Cela donne l'indice exact que je peux travailler avec jusqu'à ce que je commence à ajouter emoji au texte. Dès que les emoji sont ajoutés, il commence à y avoir un décalage pour la détection. Cela m'a conduit à regarder les rectangles englobants de glyphes que je cherchais. J'ai remarqué que les rectangles de délimitation des emoji étaient trop grands. Je mis en place le cas de test suivant pour vérifier la différence:

let emojiText = "" 
let font = UIFont.systemFontOfSize(20.0) 
let containerSize = CGSize(width: 300.0, height: 20000.0) 

let attributedString = NSAttributedString(string: emojiText, attributes: [NSFontAttributeName: font]) 

let textStorage = NSTextStorage(attributedString: attributedString) 
let layoutManager = NSLayoutManager() 
layoutManager.usesFontLeading = true 
textStorage.addLayoutManager(layoutManager) 

let textContainer = NSTextContainer(size: containerSize) 
layoutManager.addTextContainer(textContainer) 
textContainer.lineFragmentPadding = 0.0 

layoutManager.ensureLayoutForTextContainer(textContainer) 

let glyphRect = layoutManager.boundingRectForGlyphRange(NSRange(location: 0, length: attributedString.length), inTextContainer: textContainer) 
let boundingRect = attributedString.boundingRectWithSize(containerSize, options:[.UsesLineFragmentOrigin, .UsesFontLeading], context: nil) 

exécution de ce code ont donné les CGRect s suivantes:

glyphRect = (0.0, 0.0, 23.0, 28.875) 
boundingRect = (0.0, 0.0, 23.0, 23.8671875) 

Ce que cela signifie est que ces deux méthodes donnent deux tailles totalement différentes! Ce ne serait pas un problème, mais le 'offset' empile avec plus de lignes.

Example of the stacked offset

Je mis un fond violet pour le caractère du characterIndexForPoint m'a donné, a donné le rect de boundingRectForGlyphRange un contour vert et le point jaune est la taplocation réelle. Notez que le rectangle vert s'aligne bien avec un caractère différent, cependant, ce n'est pas du tout une indication, car il arrive juste de s'aligner bien dans ce cas particulier.

Est-ce que je néglige quelque chose d'évident ou est-ce un problème dans iOS?

Répondre

1

J'ai résolu le problème. Il semble que NSAttributedString.drawInRect dessine différemment de CoreText. J'utilise maintenant le code suivant pour dessiner le texte en drawRect:

let totalRange = layoutManager.glyphRangeForTextContainer(textContainer) 

layoutManager.drawBackgroundForGlyphRange(range, atPoint: CGPointZero) 
layoutManager.drawGlyphsForGlyphRange(range, atPoint: CGPointZero)