Il ya dix mois lorsque l'iPad d'origine livré, Apple a publié iOS 3.2, et pour la première fois, les développeurs iOS ont eu accès à NSAttributedString et NSMutableAttributedString, des objets conçus pour tenir les jeux avec la police, paragraphe et les informations de style. Nous n'avons plus eu à recourir à l'aide UIWebViews lourdes ou complexes Core Graphics appels pour attirer texte stylé.
Eh bien, une sorte de ...
Sur le côté Mac, NSAttributedString et son homologue NSMutableAttributedString ont été autour pendant longtemps, très longtemps, dans le cadre de la Fondation. Mais, il ya eu aussi, depuis presque aussi longtemps, sur les deux catégories de ces classes dans l'App Kit appelée Ajouts Application Kit qui ont toutes sortes de méthodes utiles supplémentaires.
Ces catégories offrent des moyens de créer des chaînes attribuées à partir différentes sortes de documents texte formatés (RTF, HTML), de créer des chaînes attribuées en spécifiant plusieurs attributs spécifiés, de tordre les attributs existants, de tirer la ficelle attribuées, et de déterminer la taille d'une attribués chaîne si elle devait être tirée.
En fait, la plupart des méthodes vraiment utiles pour ces deux classes sont contenues dans ces catégories Kit App et non pas dans les classes de base. Malheureusement, nous n'avons pas ces catégories dans le SDK iOS, ou même une version à l'échelle de retour d'entre eux. Nous devons juste les classes de base. Cela signifie que nous avons une énorme méthodes treize NSAttributedString, et l'autre treize NSMutableAttributedString.
Le cacao a attribué la marque de luxe cordes; Cocoa Touch a en magasin de la marque génériques.
Encore plus étrange, NSAttributedString a une méthode init qui prend un dictionnaire des attributs de chaîne, mais les constantes clé pour utiliser cette méthode ne sont même pas inclus dans iOS soit dans les en-têtes du public ou de la documentation. La description des méthodes qui prennent ces attributs Etat que les constantes sont dans la section Vue d'ensemble de la documentation, mais qui est réellement vrai que dans la documentation de Mac OS X, pas la documentation iOS.
En d'autres termes, vous ne pouvez pas créer un NSAttributedString ou NSMutableAttributedString utilisant initWithString: attributs: parce que vous n'avez pas les constantes dont vous avez besoin afin de préciser les différents attributs. Ce n'est pas entièrement vrai; vous êtes réellement capable d'utiliser les homologues du texte de base des constantes NSAttributedString, comme kCTForegroundColorAttributeName à la place de NSForegroundColorAttributeName, mais ce n'est pas vraiment documentée partout, et il n'est pas une science exacte 01:01 corrélation entre le NS et les attributs de chaîne CT (même si il est proche).
Cette situation est vraiment bizarre. Pomme passé par de grands efforts pour nous donner toutes les pièces de faible niveau ont besoin de faire le rendu du texte complexe, mais ne nous donne pas de niveau supérieur objets à manipuler que la plupart des fonctionnalités d'élégance. Nous avons la part du lion de tous les appels graphiques de texte de base de bas niveau et de base qui sont disponibles sur Mac OS X (toujours pas de Core Image, cependant). Pourtant, nous avons à écrire un texte de base de bas niveau et Core Graphics code pour faire l'essentiel de même les tâches les plus courantes de composition en utilisant des chaînes attribuées.
Heureusement, NSAttributedString et NSMutableAttributedString sont à la fois, sans frais, comblé de leurs homologues Core Foundation CFAttributedStringRef et CFMutableAttributedStringRef respectivement. Cela signifie que vous pouvez créer, par exemple, un CFAttributedStringRef et simplement le jeter à un pointeur NSAttributedString, puis d'appeler des méthodes sur le NSAttributedString il va fonctionner.
Mostly.
Il ya un gotcha ici. Sur iOS, UIFont et CTFont ne sont pas sans frais comblé, même si NSFont et CTFont sur le Mac sont. Vous ne pouvez pas passer un UIFont dans une fonction qui attend un CTFont et vice versa.
Pour obtenir une CTFont d'un UIFont, vous pouvez faire ceci:
Notez que le nom de cette méthode - le mot «créer» dans le nom de la fonction indique que l'objet retourné CTFont a été retenu pour vous, et vous êtes responsable de l'appel CFRelease () sur elle quand vous avez fini avec elle, pour éviter toute fuite .
En sens inverse, à partir d'un CTFont à un UIFont est seulement un peu plus impliqué. Voici une méthode catégorie sur UIFont qui permettra de créer une instance de UIFont basé sur un pointeur CTFontRef
Une fois que vous avez la possibilité de convertir les deux objets de la police dans l'autre, la création de chaînes attribuées n'est vraiment pas si mal. Voici une méthode de type par exemple sur NSMutableAttributedString qui permettra de créer une instance en prenant une NSString en plus une police, une taille de police, et une constante représentant la justification du texte désiré. Il retournera une chaîne autoreleased attribués avec les attributs du texte appliqué à toute la chaîne:
Qu'en est-il calculer l'espace nécessaire à l'établissement d'une chaîne imputables? C'est un peu plus compliquée, mais il peut être fait. Voici deux méthodes catégorie sur NSAttributedStringthat vous dira combien d'espace attribué une chaîne, il faudra quand il est dessiné avec une largeur ou une hauteur spécifiée, qui est une chose utile à connaître lors de la pose sur le texte:
NB(1): Ceci est une nouvelle version qui est à la fois plus courte, et corrige un bug avec la version originale.
NB (2): Un couple de personnes sur Twitter ont commenté que vous devez enregistrer une référence à votre CTFrameSetterRef lors du calcul de la hauteur ou la largeur et la réutilisation, car l'framesetter en cache ces calculs. Si vous utilisez un nouveau, vous avez non seulement le surcoût d'un nouvel objet, vous devrez également faire le calcul deux fois la taille. Je prévois un futur post où je montre comment dessiner des chaînes attribuées, et j'ai besoin de réfléchir sur la façon de re-architecte le code pour ce poste basé sur celui de rétroaction.
Je suppose que c'est seulement une question de temps avant qu'Apple nous donne la NSAttributedString Ajouts UIKit catégorie, ou d'un quelconque niveau supérieur de fonctionnalité. En attendant, chaque fois que vous avez à traiter avec des cordes attribué, le meilleur pari est de trouver comment faire ce que vous devez faire dans le texte de base et / ou Core Graphics (guides de programmation d'Apple fait montrer exactement comment le faire le plus commun tâches à l'aide de ces deux cadres), puis les envelopper d'une version générique de ce code dans une méthode ou de catégorie sur NSAttributedString NSMutableAttributableString.
Eh bien, une sorte de ...
Sur le côté Mac, NSAttributedString et son homologue NSMutableAttributedString ont été autour pendant longtemps, très longtemps, dans le cadre de la Fondation. Mais, il ya eu aussi, depuis presque aussi longtemps, sur les deux catégories de ces classes dans l'App Kit appelée Ajouts Application Kit qui ont toutes sortes de méthodes utiles supplémentaires.
Ces catégories offrent des moyens de créer des chaînes attribuées à partir différentes sortes de documents texte formatés (RTF, HTML), de créer des chaînes attribuées en spécifiant plusieurs attributs spécifiés, de tordre les attributs existants, de tirer la ficelle attribuées, et de déterminer la taille d'une attribués chaîne si elle devait être tirée.
En fait, la plupart des méthodes vraiment utiles pour ces deux classes sont contenues dans ces catégories Kit App et non pas dans les classes de base. Malheureusement, nous n'avons pas ces catégories dans le SDK iOS, ou même une version à l'échelle de retour d'entre eux. Nous devons juste les classes de base. Cela signifie que nous avons une énorme méthodes treize NSAttributedString, et l'autre treize NSMutableAttributedString.
Le cacao a attribué la marque de luxe cordes; Cocoa Touch a en magasin de la marque génériques.
Encore plus étrange, NSAttributedString a une méthode init qui prend un dictionnaire des attributs de chaîne, mais les constantes clé pour utiliser cette méthode ne sont même pas inclus dans iOS soit dans les en-têtes du public ou de la documentation. La description des méthodes qui prennent ces attributs Etat que les constantes sont dans la section Vue d'ensemble de la documentation, mais qui est réellement vrai que dans la documentation de Mac OS X, pas la documentation iOS.
En d'autres termes, vous ne pouvez pas créer un NSAttributedString ou NSMutableAttributedString utilisant initWithString: attributs: parce que vous n'avez pas les constantes dont vous avez besoin afin de préciser les différents attributs. Ce n'est pas entièrement vrai; vous êtes réellement capable d'utiliser les homologues du texte de base des constantes NSAttributedString, comme kCTForegroundColorAttributeName à la place de NSForegroundColorAttributeName, mais ce n'est pas vraiment documentée partout, et il n'est pas une science exacte 01:01 corrélation entre le NS et les attributs de chaîne CT (même si il est proche).
Cette situation est vraiment bizarre. Pomme passé par de grands efforts pour nous donner toutes les pièces de faible niveau ont besoin de faire le rendu du texte complexe, mais ne nous donne pas de niveau supérieur objets à manipuler que la plupart des fonctionnalités d'élégance. Nous avons la part du lion de tous les appels graphiques de texte de base de bas niveau et de base qui sont disponibles sur Mac OS X (toujours pas de Core Image, cependant). Pourtant, nous avons à écrire un texte de base de bas niveau et Core Graphics code pour faire l'essentiel de même les tâches les plus courantes de composition en utilisant des chaînes attribuées.
Heureusement, NSAttributedString et NSMutableAttributedString sont à la fois, sans frais, comblé de leurs homologues Core Foundation CFAttributedStringRef et CFMutableAttributedStringRef respectivement. Cela signifie que vous pouvez créer, par exemple, un CFAttributedStringRef et simplement le jeter à un pointeur NSAttributedString, puis d'appeler des méthodes sur le NSAttributedString il va fonctionner.
Mostly.
Il ya un gotcha ici. Sur iOS, UIFont et CTFont ne sont pas sans frais comblé, même si NSFont et CTFont sur le Mac sont. Vous ne pouvez pas passer un UIFont dans une fonction qui attend un CTFont et vice versa.
Pour obtenir une CTFont d'un UIFont, vous pouvez faire ceci:
CTFontRef CTFontCreateFromUIFont(UIFont *font)
{
CTFontRef ctFont = CTFontCreateWithName((CFStringRef)font.fontName,
font.pointSize,
NULL);
return ctFont;
}Notez que le nom de cette méthode - le mot «créer» dans le nom de la fonction indique que l'objet retourné CTFont a été retenu pour vous, et vous êtes responsable de l'appel CFRelease () sur elle quand vous avez fini avec elle, pour éviter toute fuite .
En sens inverse, à partir d'un CTFont à un UIFont est seulement un peu plus impliqué. Voici une méthode catégorie sur UIFont qui permettra de créer une instance de UIFont basé sur un pointeur CTFontRef
@implementation UIFont(MCUtilities)
+ (id)fontWithCTFont:(CTFontRef)ctFont
{
CFStringRef fontName = CTFontCopyFullName(ctFont);
CGFloat fontSize = CTFontGetSize(ctFont);
UIFont *ret = [UIFont fontWithName:(NSString *)fontName size:fontSize];
CFRelease(fontName);
return ret;
}
@endUne fois que vous avez la possibilité de convertir les deux objets de la police dans l'autre, la création de chaînes attribuées n'est vraiment pas si mal. Voici une méthode de type par exemple sur NSMutableAttributedString qui permettra de créer une instance en prenant une NSString en plus une police, une taille de police, et une constante représentant la justification du texte désiré. Il retournera une chaîne autoreleased attribués avec les attributs du texte appliqué à toute la chaîne:
+ (id)mutableAttributedStringWithString:(NSString *)string font:(UIFont *)font color:(UIColor *)color alignment:(CTTextAlignment)alignment
{
CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
if (string != nil)
CFAttributedStringReplaceString (attrString, CFRangeMake(0, 0), (CFStringRef)string);
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, CFAttributedStringGetLength(attrString)), kCTForegroundColorAttributeName, color.CGColor);
CTFontRef theFont = CTFontCreateFromUIFont(font);
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, CFAttributedStringGetLength(attrString)), kCTFontAttributeName, theFont);
CFRelease(theFont);
CTParagraphStyleSetting settings[] = {kCTParagraphStyleSpecifierAlignment, sizeof(alignment), &alignment};
CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(settings, sizeof(settings) / sizeof(settings[0]));
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, CFAttributedStringGetLength(attrString)), kCTParagraphStyleAttributeName, paragraphStyle);
CFRelease(paragraphStyle);
NSMutableAttributedString *ret = (NSMutableAttributedString *)attrString;
return [ret autorelease];
}Qu'en est-il calculer l'espace nécessaire à l'établissement d'une chaîne imputables? C'est un peu plus compliquée, mais il peut être fait. Voici deux méthodes catégorie sur NSAttributedStringthat vous dira combien d'espace attribué une chaîne, il faudra quand il est dessiné avec une largeur ou une hauteur spécifiée, qui est une chose utile à connaître lors de la pose sur le texte:
NB(1): Ceci est une nouvelle version qui est à la fois plus courte, et corrige un bug avec la version originale.
NB (2): Un couple de personnes sur Twitter ont commenté que vous devez enregistrer une référence à votre CTFrameSetterRef lors du calcul de la hauteur ou la largeur et la réutilisation, car l'framesetter en cache ces calculs. Si vous utilisez un nouveau, vous avez non seulement le surcoût d'un nouvel objet, vous devrez également faire le calcul deux fois la taille. Je prévois un futur post où je montre comment dessiner des chaînes attribuées, et j'ai besoin de réfléchir sur la façon de re-architecte le code pour ce poste basé sur celui de rétroaction.
- (CGFloat)boundingWidthForHeight:(CGFloat)inHeight
{
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString( (CFMutableAttributedStringRef) self);
CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(CGFLOAT_MAX, inHeight), NULL);
CFRelease(framesetter);
return suggestedSize.width;
}
- (CGFloat)boundingHeightForWidth:(CGFloat)inWidth
{
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString( (CFMutableAttributedStringRef) self);
CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(inWidth, CGFLOAT_MAX), NULL);
CFRelease(framesetter);
return suggestedSize.height;
}Je suppose que c'est seulement une question de temps avant qu'Apple nous donne la NSAttributedString Ajouts UIKit catégorie, ou d'un quelconque niveau supérieur de fonctionnalité. En attendant, chaque fois que vous avez à traiter avec des cordes attribué, le meilleur pari est de trouver comment faire ce que vous devez faire dans le texte de base et / ou Core Graphics (guides de programmation d'Apple fait montrer exactement comment le faire le plus commun tâches à l'aide de ces deux cadres), puis les envelopper d'une version générique de ce code dans une méthode ou de catégorie sur NSAttributedString NSMutableAttributableString.
Aucun commentaire:
Enregistrer un commentaire