aligner verticalement du text dans un CATextLayer?

Je travaille sur un CATextLayer que je veux utiliser dans Mac et iOS. Puis-je contrôler l'alignment vertical du text dans la couche?

Dans ce cas particulier, je veux le centrer verticalement – mais des informations sur d'autres alignments verticaux seraient également intéressantes.

EDIT: J'ai trouvé ça , mais je ne peux pas le faire fonctionner.

La réponse correcte, comme vous l'avez déjà trouvé, est ici dans Objective-C et fonctionne pour iOS . Cela fonctionne en sous- CATextLayer le CATextLayer et en drawInContext fonction drawInContext .

Cependant, j'ai apporté quelques améliorations au code , comme indiqué ci-dessous, en utilisant le code de David Hoerl comme base. Les changements viennent uniquement dans le recalcul de la position verticale du text représenté par le yDiff . Je l'ai testé avec mon propre code.

Voici le code pour les users de Swift:

 class LCTextLayer : CATextLayer { // REF: http://lists.apple.com/archives/quartz-dev/2008/Aug/msg00016.html // CREDIT: David Hoerl - https://github.com/dhoerl // USAGE: To fix the vertical alignment issue that currently exists within the CATextLayer class. Change made to the yDiff calculation. override init!() { super.init() } override init!(layer: AnyObject!) { super.init(layer: layer) } required init(coder aDecoder: NSCoder) { super.init(layer: aDecoder) } override func drawInContext(ctx: CGContext!) { let height = self.bounds.size.height let fontSize = self.fontSize let yDiff = (height-fontSize)/2 - fontSize/10 CGContextSaveGState(ctx) CGContextTranslateCTM(ctx, 0.0, yDiff) super.drawInContext(ctx) CGContextRestoreGState(ctx) } } 

Peut-être en retard pour la réponse, mais vous pouvez calculer la taille du text, puis définir la position de textLayer. Vous devez également placer le mode textLayer textAligment sur "center"

 CGRect labelRect = [text boundingRectWithSize:view.bounds.size options:NSSsortingngDrawingUsesLineFragmentOrigin atsortingbutes:@{ NSFontAtsortingbuteName : [UIFont fontWithName:@"HelveticaNeue" size:17.0] } context:nil]; CATextLayer *textLayer = [CATextLayer layer]; [textLayer setSsortingng:text]; [textLayer setForegroundColor:[UIColor redColor].CGColor]; [textLayer setFrame:labelRect]; [textLayer setFont:CFBridgingRetain([UIFont fontWithName:@"HelveticaNeue" size:17.0].fontName)]; [textLayer setAlignmentMode:kCAAlignmentCenter]; [textLayer setFontSize:17.0]; textLayer.masksToBounds = YES; textLayer.position = CGPointMake(CGRectGetMidX(view.bounds), CGRectGetMidY(view.bounds)); [view.layer addSublayer:textLayer]; 

C'est une réponse tardive, mais j'ai la même question ces jours-ci, et j'ai résolu le problème avec l'enquête suivante.

L'alignment vertical dépend du text que vous devez dessiner et de la police que vous utilisez, il n'y a donc pas de solution à sens unique pour le rendre vertical dans tous les cas.

Mais nous pouvons toujours calculer le point médian vertical pour différents cas.

Selon Apple à propos de la manipulation de text dans iOS , nous devons savoir comment le text est dessiné.

Par exemple, j'essaie de faire un alignment vertical pour les strings de la semaine: dim, lun, mar, ….

Pour ce cas, la hauteur du text dépend de la hauteur du cap , et il n'y a pas de descente pour ces caractères. Donc, si nous devons aligner ces texts sur le milieu, nous pouvons calculer le décalage du caractère haut de cap, par exemple la position du haut du caractère "S".

Selon la figure ci-dessous:

figue

L'espace supérieur pour le caractère "S" majuscule serait

 font.ascender - font.capHeight 

Et l'espace inférieur pour le caractère «S» capital serait

 font.descender + font.leading 

Donc, nous devons déplacer "S" un peu du haut par:

 y = (font.ascender - font.capHeight + font.descender + font.leading + font.capHeight) / 2 

Cela équivaut à:

 y = (font.ascender + font.descender + font.leading) / 2 

Ensuite, je peux faire le text vertical aligner le milieu.

Conclusion:

  1. Si votre text ne comprend aucun caractère, dépasser la ligne de base, par exemple "p", "j", "g", et aucun caractère au-dessus de la hauteur de la casquette, par exemple "f". Vous pouvez utiliser la formule ci-dessus pour aligner le text verticalement.

     y = (font.ascender + font.descender + font.leading) / 2 
  2. Si votre text inclut un caractère sous la ligne de base, par exemple "p", "j", et qu'aucun caractère ne dépasse le haut de la hauteur du chapeau, par exemple "f". Alors la formule verticale serait:

     y = (font.ascender + font.descender) / 2 
  3. Si votre text n'inclut pas le caractère dessiné sous la ligne de base, par exemple "j", "p", et inclut le caractère dessiné au-dessus de la ligne de hauteur du chapeau, par exemple "f". Alors y serait:

     y = (font.descender + font.leading) / 2 
  4. Si tous les caractères apparaissaient dans votre text, alors y équivaut à:

     y = font.leading / 2 

merci @iamktothed, ça marche. Voici la version 3 de Swift:

 class CXETextLayer : CATextLayer { override init() { super.init() } override init(layer: Any) { super.init(layer: layer) } required init(coder aDecoder: NSCoder) { super.init(layer: aDecoder) } override func draw(in ctx: CGContext) { let height = self.bounds.size.height let fontSize = self.fontSize let yDiff = (height-fontSize)/2 - fontSize/10 ctx.saveGState() ctx.translateBy(x: 0.0, y: yDiff) super.draw(in: ctx) ctx.restoreGState() } } 

Version Swift 3 pour les strings régulières et atsortingbuées.

 class ECATextLayer: CATextLayer { override open func draw(in ctx: CGContext) { let yDiff: CGFloat let fontSize: CGFloat let height = self.bounds.height if let atsortingbutedSsortingng = self.ssortingng as? NSAtsortingbutedSsortingng { fontSize = atsortingbutedSsortingng.size().height yDiff = (height-fontSize)/2 } else { fontSize = self.fontSize yDiff = (height-fontSize)/2 - fontSize/10 } ctx.saveGState() ctx.translateBy(x: 0.0, y: yDiff) super.draw(in: ctx) ctx.restoreGState() } } 

Il n'y a donc pas de moyen "direct" de le faire mais vous pouvez accomplir la même chose en utilisant des mesures textuelles:

http://developer.apple.com/library/ios/#documentation/UIKit/Reference/NSSsortingng_UIKit_Additions/Reference/Reference.html

… par exemple, trouvez la taille du text puis utilisez cette information pour le placer où vous voulez dans le calque parent. J'espère que cela t'aides.

Vous devez savoir où CATextLayer mettra la ligne de base de votre text. Une fois que vous le savez, décalez le système de coordonnées au sein de la couche, c'est-à-dire ajustez bounds.origin.y par la différence entre l'endroit où la ligne de base se trouve normalement et l'endroit où vous voulez qu'elle soit, étant donné les mésortingques de la police.

CATextLayer est un peu une boîte noire et de find où la ligne de base sera assis est un peu difficile – voir ma réponse ici pour iOS – Je n'ai aucune idée de ce que le comportement est sur Mac.

Le code de gbk fonctionne. ci-dessous est le code de gbk mis à jour pour XCode 8 beta 6. Actuel au 1 oct. 2016

Étape 1. Sous-class CATextLayer. Dans le code ci-dessous j'ai nommé la sous-class "MyCATextLayer" En dehors de votre class de controller de vue copyr / coller le code ci-dessous.

 class MyCATextLayer: CATextLayer { // REF: http://lists.apple.com/archives/quartz-dev/2008/Aug/msg00016.html // CREDIT: David Hoerl - https://github.com/dhoerl // USAGE: To fix the vertical alignment issue that currently exists within the CATextLayer class. Change made to the yDiff calculation. override init() { super.init() } required init(coder aDecoder: NSCoder) { super.init(layer: aDecoder) } override func draw(in ctx: CGContext) { let height = self.bounds.size.height let fontSize = self.fontSize let yDiff = (height-fontSize)/2 - fontSize/10 ctx.saveGState() ctx.translateBy(x: 0.0, y: yDiff) super.draw(in: ctx) ctx.restoreGState() } } 

Étape 2. Dans votre class de controller de vue dans votre file ".swift", créez votre CATextLabel. Dans l'exemple de code, j'ai nommé la sous-class "MyDopeCATextLayer".

 let MyDopeCATextLayer: MyCATextLayer = MyCATextLayer() 

Étape 3. Définissez votre nouveau CATextLayer avec le text / la couleur / les limites / le cadre souhaités.

 MyDopeCATextLayer.ssortingng = "Hello World" // displayed text MyDopeCATextLayer.foregroundColor = UIColor.purple.cgColor //color of text is purple MyDopeCATextLayer.frame = CGRect(x: 0, y:0, width: self.frame.width, height: self.frame.height) MyDopeCATextLayer.font = UIFont(name: "HelveticaNeue-UltraLight", size: 5) //5 is ignored, set actual font size using ".fontSize" (below) MyDopeCATextLayer.fontSize = 24 MyDopeCATextLayer.alignmentMode = kCAAlignmentCenter //Horizontally centers text. text is automatically centered vertically because it's set in subclass code MyDopeCATextLayer.contentsScale = UIScreen.main.scale //sets "resolution" to whatever the device is using (prevents fuzzyness/blurryness) 

Étape 4. fait

Le code de Swift 3, basé sur le code @iamktothed

Si vous utilisez une string atsortingbuée pour définir les propriétés de la police, vous pouvez utiliser la fonction size () de NSAtsortingbutedSsortingng pour calculer la hauteur de la string. Je pense que ce code résout également les problèmes décrits par @Enix

 class LCTextLayer: CATextLayer { override init() { super.init() } override init(layer: Any) { super.init(layer: layer) } required init(coder aDecoder: NSCoder) { super.init(layer: aDecoder) } override open func draw(in ctx: CGContext) { if let atsortingbutedSsortingng = self.ssortingng as? NSAtsortingbutedSsortingng { let height = self.bounds.size.height let ssortingngSize = atsortingbutedSsortingng.size() let yDiff = (height - ssortingngSize.height) / 2 ctx.saveGState() ctx.translateBy(x: 0.0, y: yDiff) super.draw(in: ctx) ctx.restoreGState() } } } 

Le mieux que je puisse dire, la réponse à ma question est "Non".