3

I am attempting to create text that has an outline. I am currently using SKLabelNode with NSAttributedString, which you can now do in SpriteKit as of iOS 11. The problem is, if the stroke width is too thick, then the outline gets cut off by what appears to be the bounding rectangle of the SKLabelNode. Please see below for the image and code.

Cutoff font

extension SKLabelNode {

    func addStroke(_ strokeColor:UIColor) {

        let font = UIFont(name: self.fontName!, size: self.fontSize)
        let attributes:[NSAttributedStringKey:Any] = [.strokeColor: strokeColor, .strokeWidth: 20.0, .font: font!]
        let attributedString = NSMutableAttributedString(string: " \(self.text!) ", attributes: attributes)
        let label1 = SKLabelNode()
        label1.horizontalAlignmentMode = self.horizontalAlignmentMode
        label1.text = self.text
        label1.zPosition = -1
        label1.attributedText = attributedString
        self.addChild(label1)
    }
}

I looked at expanding the frame of the SKLabelNode serving as the border text, but that is a get-only property. I tried to add leading/trailing spaces, but they appear to be automatically trimmed. Using a negative value for strokeWidth works but creates an inner stroke, I'd prefer to have an outer stroke.

Any ideas? Thanks in advance for the help! Mike

Andy Jazz
  • 49,178
  • 17
  • 136
  • 220
MikeL
  • 163
  • 10
  • 1
    Do you need to create a label node inside the label node to make this happen? Is that how you get the outline? It looks like the one labelnode size is constraining the other one, is that the issue ? – bolnad Jan 24 '18 at 00:59
  • Thank you for the response. The outline label just has to be behind the text label in order to get this effect. I had tried to add it as a separate node (not a child of the text label) but ended up with the same results. – MikeL Jan 24 '18 at 02:32
  • 1
    ok i was going to suggest using an SKNode as the "container" for the 2, but if you've tried that then i'm not sure. good luck! – bolnad Jan 24 '18 at 03:09
  • 2
    It's not a fully finished framework. Not even close. So you get things like NSAttributedString added, but not finished. And there's no testing, nor transparency to permit you to know this before you waste time presuming something works. Apple's arrogance. If you need dynamic type with visual effects, you're pretty much out of luck. If you need dynamic type with dynamic effects, Sprite Kit might have that in 2028. – Confused Jan 24 '18 at 13:48

1 Answers1

0
  1. You shouldn't need to create a separate node for the stroke.
  2. Use negative width values to only render the stroke without fill.
  3. Use .foregroundColor to fill.
  4. You should first check to see if an attributed string is already present to ensure you do not clobber it.

Here is the code:

extension SKLabelNode {

   func addStroke(color:UIColor, width: CGFloat) {

        guard let labelText = self.text else { return }

        let font = UIFont(name: self.fontName!, size: self.fontSize)

        let attributedString:NSMutableAttributedString
        if let labelAttributedText = self.attributedText {
            attributedString = NSMutableAttributedString(attributedString: labelAttributedText)
        } else {
            attributedString = NSMutableAttributedString(string: labelText)
        }

        let attributes:[NSAttributedStringKey:Any] = [.strokeColor: color, .strokeWidth: -width, .font: font!, .foregroundColor: self.fontColor!]
        attributedString.addAttributes(attributes, range: NSMakeRange(0, attributedString.length))

        self.attributedText = attributedString
   }
}
Nader Eloshaiker
  • 587
  • 5
  • 18