Align multiple SKLabelNodes by Baseline

2019-07-19 06:56发布

问题:

I have a collection of SKLabelNodes. Each node represents a letter of a word. Each node is the child of an SKSpriteNode. The spriteNodehas an explicit hight set on it (the hight returned by [text sizeWithAttributes:@{NSFontAttributeName : font}];), and has the same width as the labelNode.

The labelNode is then centred inside the spriteNode, and has verticalAlignmentMode = SKLabelVerticalAlignmentModeBaseline. At a later stage, I will need to set a background image on each letter (which will be done using the spriteNode). For testing purposes, I am using a solid colour, making the problem apparent:

As you can see, the lower part of the letter 'y' is showing bellow the container spriteNode. The same thing happens with 'g's and other letters. I should also explain that each letterNode (that is, the spriteNode and child labelNode) is centred vertically, and spaced out horizontally, inside another SKSpriteNode, used to contain all the letters for a word.

Code that creates the letterNode:

SKLabelNode *labelNode = [SKLabelNode labelNodeWithText:text];
labelNode.fontName = font.fontName;
labelNode.fontSize = font.pointSize;
labelNode.fontColor = colour;
labelNode.position = CGPointMake(0, -floor(height/2));
// height is the same explicit height used to create the spriteNode.

SNLetterNode *letter = [SNLetterNode spriteNodeWithColor:[UIColor lightGrayColor] size:CGSizeMake(labelNode.frame.size.width, height)];
letter.letter = text;
letter.labelNode = labelNode;
letter.size = CGSizeMake(self.labelNode.frame.size.width, height);

The SKSpriteNode that contains all the letters for a word is created like so:

CGSize fullWordSize = [text sizeWithAttributes:@{NSFontAttributeName : font}];

SNWordNode *word = [SNWordNode spriteNodeWithColor:[UIColor clearColor] size:fullWordSize];
word.letterNodes = letterNodes;
word.text = text;

I believe the problem is being caused by the way I am positioning and/or sizing the label and spriteNodes. I have tried using different verticalAlignmentModes, and repositioning the labels based on that, all to no avail. If I knew of a way to align the nodes based on the baseline of the text, that would be a start.

What I would like to happen, is for the grey background to extend down, covering the lower part of the 'y', and for that to happen on all letterNodes (regardless of whether they require it, like the 'y'). And for the text to still be aligned by baseline.

Any help would be much appreciated,

Thanks in advance.

回答1:

So it turns out, the part of the (in my example) 'y' that was appearing bellow the border is called a "descender", according to Apple's docs (https://developer.apple.com/library/ios/Documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/TypoFeatures/TextSystemFeatures.html).

UIFont has a property on it, called descender, and it gives you the highest value the descent can be. I used that to increase the size of the SKSpriteNode containing the SKLabelNode, and properly centre the label.



回答2:

Just wanted to note I posted my approach (for a similar issue) here. My solution is based on your answer: https://stackoverflow.com/a/51682287/250164