J'ai une question concernant les coins arrondis et la couleur d'arrière-plan du texte pour un UIView
personnalisé.
Fondamentalement, j'ai besoin d'obtenir un effet comme celui-ci (image jointe - notez les coins arrondis d'un côté) dans une UIView personnalisée:
Je pense que l'approche à utiliser est la suivante:
Cependant, je ne sais pas si c'est la seule solution (ou d'ailleurs, si c'est la solution la plus efficace).
Utiliser un UIWebView
n'est pas une option, donc je dois le faire dans un UIView
personnalisé.
Ma question étant, est-ce la meilleure approche à utiliser, et suis-je sur la bonne voie? Ou est-ce que je manque quelque chose d'important ou que je m'y trompe?
J'ai réussi à obtenir l'effet ci-dessus, alors j'ai pensé publier une réponse pour la même chose.
Si quelqu'un a des suggestions pour rendre cela plus efficace, n'hésitez pas à contribuer. Je ne manquerai pas de marquer votre réponse comme la bonne. :)
Pour ce faire, vous devrez ajouter un "attribut personnalisé" à NSAttributedString
.
Fondamentalement, cela signifie que vous pouvez ajouter n'importe quelle paire clé-valeur, tant que c'est quelque chose que vous pouvez ajouter à une instance NSDictionary
. Si le système ne reconnaît pas cet attribut, il ne fait rien. C'est à vous, en tant que développeur, de fournir une implémentation et un comportement personnalisés pour cet attribut.
Aux fins de cette réponse, supposons que j'ai ajouté un attribut personnalisé appelé: @"MyRoundedBackgroundColor"
Avec une valeur de [UIColor greenColor]
.
Pour les étapes qui suivent, vous aurez besoin d'avoir une compréhension de base de la façon dont CoreText
fait avancer les choses. Consultez Guide de programmation du texte de base d'Apple pour comprendre ce qu'est un cadre/une ligne/un glyphe/un glyphe, etc.
Voici donc les étapes:
NSAttributedString
.CTFramesetter
en utilisant cette instance NSAttributedString
.drawRect:
CTFrame
à partir de CTFramesetter
. CGPathRef
pour créer le CTFrame
. Faites en sorte que CGPath
soit le même que le cadre dans lequel vous souhaitez dessiner le texte.CTFrameGetLines(...)
, obtenez toutes les lignes dans le CTFrame
que vous venez de créer.CTFrameGetLineOrigins(...)
, obtenez toutes les origines de ligne pour CTFrame
.for loop
- pour chaque ligne du tableau de CTLine
...CTLine
à l'aide de CGContextSetTextPosition(...)
.CTLineGetGlyphRuns(...)
récupérez toutes les exécutions de glyphes (CTRunRef
) à partir de CTLine
.for loop
- pour chaque glyphRun dans le tableau de CTRun
...CTRunGetStringRange(...)
.CTRunGetTypographicBounds(...)
.CTLineGetOffsetForStringIndex(...)
.runBounds
) en utilisant les valeurs renvoyées par les fonctions susmentionnées. CTRunGetTypographicBounds(...)
nécessite des pointeurs vers des variables pour stocker la "montée" et la "descente" du texte. Vous devez les ajouter pour obtenir la hauteur de course.CTRunGetAttributes(...)
.runBounds
).runBounds
, nous savons quelle zone nous voulons peindre - maintenant nous pouvons utiliser n'importe laquelle des méthodes CoreGraphis
/UIBezierPath
pour dessiner et remplir un rect avec des coins arrondis.UIBezierPath
a une méthode de classe de commodité appelée bezierPathWithRoundedRect:byRoundingCorners:cornerRadii:
qui vous permet de contourner des coins spécifiques. Vous spécifiez les coins à l'aide de masques de bits dans le 2e paramètre.CTRunDraw(...)
.En ce qui concerne la détection de l'extension de la plage d'attributs sur plusieurs exécutions, vous pouvez obtenir l'intégralité de la plage effective de votre attribut personnalisé lorsque la première exécution rencontre l'attribut. Si vous constatez que la longueur de la plage efficace maximale de votre attribut est supérieure à la longueur de votre course, vous devez peindre des angles vifs sur le côté droit (pour un script de gauche à droite). Plus de mathématiques vous permettront également de détecter le style de coin en surbrillance pour la ligne suivante. :)
Ci-joint une capture d'écran de l'effet. La boîte en haut est un UITextView
standard, pour lequel j'ai défini l'attributText. La case en bas est celle qui a été implémentée à l'aide des étapes ci-dessus. La même chaîne attribuée a été définie pour les deux textViews.
Encore une fois, s'il existe une meilleure approche que celle que j'ai utilisée, faites-le moi savoir! :RÉ
J'espère que cela aide la communauté. :)
À votre santé!