SKLabelNode - how to center align when more than one line?

I solved this issue by setting attributedText to SKLabelNode. Seemed like the easiest way to do it, hope Apple fixes this issue soon.

Swift 4

let attrString = NSMutableAttributedString(string: yourString)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.alignment = .center
let range = NSRange(location: 0, length: yourString.count)
attrString.addAttribute(NSAttributedStringKey.paragraphStyle, value: paragraphStyle, range: range)
attrString.addAttributes([NSAttributedStringKey.foregroundColor : UIColor.black, NSAttributedStringKey.font : UIFont.systemFont(ofSize: 30)], range: range)
yourLabelNode.attributedText = attrString

Following up - I posted a link instead of code, which is kind of a no-no. I don't have a big rep (noob), so I also can't edit yet :)

I recently discovered that you can overlay UIKit on top of scenekit (probably Sprite Kit too). I've tried it and it works with no loss in FPS, so I'm removing all of my Spritekit overlays (menus/labels) and using the UIKit basics (UIButton, UILabel). If this is of interest, I can share some code. I'm still figuring things out, but far enough into it that I think it's going to work.


It seems that Apple's SKLabel simply does not center multi-line text. (As of 2018.)

The behavior can only be described as broken - the second and latter lines just flush left no matter what setting.

One solution is to use a "second label", example below.

Later...

@MartinŠkorc seems to have discovered you can use AttributedString with SKLabels - so, great! Thanks Martin!

import SpriteKit

class StupidMultilineSKLabelNode: SKLabelNode {
    
    // Apple's SKLabel does not center multi-line text
    
    // this class works around the problem by making
    // a "sub" SKLabel for the second line
    
    // if the .text includes a newline, a line break,
    // this class will present it as a two-line SKLabel,
    // but properly centered (each line itself centered).
    // (this example allows just the one extra line)
    
    // please note,
    // this is not meant to be a generalized class;
    // rather it is meant to work quick in a specific case.
    // you can change it as needed
    
    // using a "second label" does seem to be the only solution
    // until Apple address the issue
    
    var stupidExtraLabel: SKLabelNode
    
    override init() {
        
        stupidExtraLabel = SKLabelNode()
        super.init()
        
        stupidExtraLabel.basicSettings()
        // the simplest approach: in "basicSettings" simply set
        // your point size, font, color, etc etc as you wish
        // just always use that call to set all labels in the project

        stupidExtraLabel.position = CGPoint(x: 0, y: -10)
        stupidExtraLabel.text = ""
        
        self.addChild(stupidExtraLabel)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override var alpha: CGFloat {
        
        didSet {
            
            super.alpha = alpha
            stupidExtraLabel.alpha = alpha
        }
    }
    
    override var fontColor: UIColor? {
        
        didSet {
            
            super.fontColor = fontColor
            stupidExtraLabel.fontColor = fontColor
        }
    }
    
    override var text: String? {
        
        didSet {
            
            let lines: [String] = text!.components(separatedBy: ["\n"])
            super.text = ""
            stupidExtraLabel.text = ""
            if lines.count > 0 { super.text = lines[0] }
            if lines.count > 1 { stupidExtraLabel.text = lines[1] }
            
            stupidExtraLabel.position = CGPoint(x: 0, y: -10)
        }
    }
}