Redimensionnez CATextLayer pour ajuster le texte sur iOS

Toutes mes recherches jusqu'à ce jour semble indiquer qu'il n'est pas possible de le faire avec précision. Les deux seules options qui m'ont été offertes au départ étaient:

a) Utilisation d'un gestionnaire de mise en page pour CATextLayer - non disponible sur iOS à partir de 4.0

b) utiliser sizeWithFont:constrainedToSize:lineBreakMode: et ajuster le cadre du CATextLayer en fonction de la taille retournée ici.

L'Option (b), étant l'approche la plus simple, devrait fonctionner. Après tout, il fonctionne parfaitement avec UILabels. Mais quand J'ai appliqué le même calcul de cadre à CATextLayer, le cadre s'est toujours avéré être un peu plus grand que prévu ou nécessaire.

comme il s'avère, L'espacement des lignes dans CATextLayers et UILabels (pour la même police et la même taille) est différent. Par conséquent, sizeWithFont (dont les calculs d'espacement des lignes concordent avec ceux des UILabels) ne renvoie pas la taille prévue pour les joueurs de Catex.

C'est plus éprouvé en imprimant le même texte avec un UILabel, par rapport à un CATextLayer et en comparant les résultats. Le texte de la première ligne se superpose parfaitement (c'est la même police), mais L'espacement des lignes dans CATextLayer est juste un peu plus court que dans UILabel. (Désolé, Je ne peux pas télécharger un screenshot en ce moment car ceux que j'ai déjà contiennent des données confidentielles, et je n'ai pas le temps de faire un projet d'échantillon pour obtenir des screenshots propres. Je les mettrai en ligne plus tard pour la postérité, quand j'aurai le temps)

c'est une différence étrange, mais j'ai pensé qu'il serait possible d'ajuster l'espacement dans le CATextLayer en spécifiant l'attribut approprié pour le NSAttributedString que j'utilise là, mais cela ne semble pas être le cas. Je regarde dans CFStringAttributes.h je n'arrive pas à trouver un seul attribut qui pourrait être relié à l'espacement des lignes.

Conclusion:

il semble donc qu'il n'est pas possible D'utiliser CATextLayer sur iOS dans un scénario où la couche est nécessaire pour s'adapter à son texte. Suis-je le droit sur ce ou ai-je raté quelque chose?

P. S:

  1. la raison pour laquelle je voulais utiliser CATextLayer et NSAttributedString est que la chaîne à afficher doit être colorée différemment à différents points. Je suppose que je devrais retourner tirer les ficelles à la main comme toujours....bien sûr, il ya toujours l'option de hacking les résultats de sizeWithFont pour obtenir le bon la hauteur de la ligne.

  2. abuser un peu des balises 'code' pour rendre le message plus lisible.

  3. Je ne suis pas capable d'étiqueter le post avec 'CATextLayer' - étonnamment, il n'existe pas de telles étiquettes pour le moment. Si quelqu'un avec assez de réputation saute dans ce post, s'il vous plaît tag en conséquence.

20
demandé sur Nolan Amy 2011-06-01 12:07:46

3 réponses

essaye ceci:

- (CGFloat)boundingHeightForWidth:(CGFloat)inWidth withAttributedString:(NSAttributedString *)attributedString {
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString( (CFMutableAttributedStringRef) attributedString); 
    CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(inWidth, CGFLOAT_MAX), NULL);
    CFRelease(framesetter);
    return suggestedSize.height;
}

vous devrez convertir votre NSString en NSAttributedString. En cas d' CATextLayer, vous pouvez utiliser CATextLayer sous-classe de la méthode:

- (NSAttributedString *)attributedString {

    // If string is an attributed string
    if ([self.string isKindOfClass:[NSAttributedString class]]) {
        return self.string;
    }

    // Collect required parameters, and construct an attributed string
    NSString *string = self.string;
    CGColorRef color = self.foregroundColor;
    CTFontRef theFont = self.font;
    CTTextAlignment alignment;

    if ([self.alignmentMode isEqualToString:kCAAlignmentLeft]) {
        alignment = kCTLeftTextAlignment;

    } else if ([self.alignmentMode isEqualToString:kCAAlignmentRight]) {
        alignment = kCTRightTextAlignment;

    } else if ([self.alignmentMode isEqualToString:kCAAlignmentCenter]) {
        alignment = kCTCenterTextAlignment;

    } else if ([self.alignmentMode isEqualToString:kCAAlignmentJustified]) {
        alignment = kCTJustifiedTextAlignment;

    } else if ([self.alignmentMode isEqualToString:kCAAlignmentNatural]) {
        alignment = kCTNaturalTextAlignment;
    }

    // Process the information to get an attributed string
    CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);

    if (string != nil)
        CFAttributedStringReplaceString (attrString, CFRangeMake(0, 0), (CFStringRef)string);

    CFAttributedStringSetAttribute(attrString, CFRangeMake(0, CFAttributedStringGetLength(attrString)), kCTForegroundColorAttributeName, color);
    CFAttributedStringSetAttribute(attrString, CFRangeMake(0, CFAttributedStringGetLength(attrString)), kCTFontAttributeName, 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];
}

HTH.

15
répondu Mustafa 2011-12-19 09:54:58

j'ai une solution beaucoup plus facile, qui peut ou ne peut pas fonctionner pour vous.

si vous ne faites rien de spécial avec le CATextLayer que vous ne pouvez pas faire un UILabel, faites un CALayer et ajoutez la couche de L'UILabel au CALayer

UILabel*label = [[UILabel alloc]init];

//Do Stuff to label

CALayer *layer = [CALayer layer];

//Set Size/Position

[layer addSublayer:label.layer];

//Do more stuff to layer
2
répondu Matt Foley 2012-01-28 21:17:05

cette page m'en a donné assez pour créer un simple CATextLayer centré horizontalement:http://lists.apple.com/archives/quartz-dev/2008/Aug/msg00016.html

- (void)drawInContext:(CGContextRef)ctx {
  CGFloat height, fontSize;

  height = self.bounds.size.height;
  fontSize = self.fontSize;

  CGContextSaveGState(ctx);
  CGContextTranslateCTM(ctx, 0.0, (fontSize-height)/2.0 * -1.0);
  [super drawInContext:ctx];
  CGContextRestoreGState(ctx);
}
-2
répondu orta 2011-09-30 07:31:37