19

I'm trying hard to find a way to simply add an outline/stroke/contour to my UILabel text. Talking about a stroke around the letters of the text not around the background of a UILabel.

I'm using swift 3 and I'd like to outline my text directly into my subclass: UILabel.

I found multiple answers suggesting this way to do things :

let strokeTextAttributes = [
        NSStrokeColorAttributeName : UIColor.black,
        NSForegroundColorAttributeName : UIColor.white,
        NSStrokeWidthAttributeName : -4.0,
        NSFontAttributeName : UIFont.boldSystemFont(ofSize: 30)
    ]

    self.attributedText = NSMutableAttributedString(string: self.text!, attributes: strokeTextAttributes)

But the thing is that it doesn't work. My text is still the same with no outline...

Could anyone help me here ? That would be a great thing :)

Thanks a lot. Cheers guys.

iji
  • 392
  • 1
  • 2
  • 13

6 Answers6

28

This code works for me.

Swift 3

let strokeTextAttributes = [
  NSStrokeColorAttributeName : UIColor.black,
  NSForegroundColorAttributeName : UIColor.white,
  NSStrokeWidthAttributeName : -4.0,
  NSFontAttributeName : UIFont.boldSystemFont(ofSize: 30)
] as [String : Any]

myLabel.attributedText = NSMutableAttributedString(string: "Test me i have color.", attributes: strokeTextAttributes)

Output like this...



Swift 4.2 & 5.1

let strokeTextAttributes = [
  NSAttributedString.Key.strokeColor : UIColor.red,
  NSAttributedString.Key.foregroundColor : UIColor.white,
  NSAttributedString.Key.strokeWidth : -4.0,
  NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 30)]
  as [NSAttributedString.Key : Any]

labelOutLine.attributedText = NSMutableAttributedString(string: "Your outline text", attributes: strokeTextAttributes)

enter image description here

Community
  • 1
  • 1
Anand Nimje
  • 6,163
  • 4
  • 24
  • 43
12

@anandnimje answer converted to Swift 4.2 and wrapped it into a function:

public func stroke(font: UIFont, strokeWidth: Float, insideColor: UIColor, strokeColor: UIColor) -> [NSAttributedStringKey: Any]{
    return [
        NSAttributedStringKey.strokeColor : strokeColor,
        NSAttributedStringKey.foregroundColor : insideColor,
        NSAttributedStringKey.strokeWidth : -strokeWidth,
        NSAttributedStringKey.font : font
        ]
}

Usage:

label.attributedText = NSMutableAttributedString(string: "Hello World", 
attributes: stroke(font: UIFont(name: "SourceSansPro-Black", size: 20)!, 
strokeWidth: 4, insideColor: .white, strokeColor: .black))

Make sure you have the right name for your UIFont, else it crashes. Should never be a problem if you have the right name.

J. Doe
  • 12,159
  • 9
  • 60
  • 114
  • The number is (from the documentation): *NSNumber containing floating point value, in percent of font point size, default 0: no stroke; positive for stroke alone, negative for stroke and fill (a typical value for outlined text would be 3.0)*. – lenooh Nov 02 '18 at 16:46
8

Here you have class with implementation, copy and paste to playgrond for test:

    class StrokedLabel: UILabel {

        var strockedText: String = "" {
            willSet(newValue) {
                let strokeTextAttributes = [
                    NSStrokeColorAttributeName : UIColor.black,
                    NSForegroundColorAttributeName : UIColor.white,
                    NSStrokeWidthAttributeName : -4.0,
                    NSFontAttributeName : UIFont.boldSystemFont(ofSize: 30)
                    ] as [String : Any]

                let customizedText = NSMutableAttributedString(string: newValue,
                                                               attributes: strokeTextAttributes)


                attributedText = customizedText
            }
        }
    }


//////////// PLAYGROUND IMPLEMENTATION PART /////////
    let text = "Stroked text"

// UILabel subclass initialization
    let label = StrokedLabel(frame: CGRect(x: 0, y: 0, width: 200, height: 50))
// simple assign String to 'strockedText' property to see the results
    label.strockedText = text

    label.backgroundColor = UIColor.white


    label

Swift 4.2

import UIKit

class StrokedLabel: UILabel {

var strockedText: String = "" {
    willSet(newValue) {
        let strokeTextAttributes : [NSAttributedString.Key : Any] = [
            NSAttributedString.Key.strokeColor : UIColor.black,
            NSAttributedString.Key.foregroundColor : UIColor.white,
            NSAttributedString.Key.strokeWidth : -4.0,
            NSAttributedString.Key.font : UIFont.boldSystemFont(ofSize: 30)
            ] as [NSAttributedString.Key  : Any]

        let customizedText = NSMutableAttributedString(string: newValue,
                                                       attributes: strokeTextAttributes)


        attributedText = customizedText
    }
}

}

//////////// PLAYGROUND IMPLEMENTATION PART /////////
  let text = "Stroked text"

  // UILabel subclass initialization
  let label = StrokedLabel(frame: CGRect(x: 0, y: 0, width: 200, height: 50))
  // simple assign String to 'strockedText' property to see the results
  label.strockedText = text

  label.backgroundColor = UIColor.clear


  label

Maybe refactoring for this class will be welcomed, but should work for you at this form

enter image description here

As you can see usage is very convenient.

mohsen
  • 4,698
  • 1
  • 33
  • 54
Robert
  • 3,790
  • 1
  • 27
  • 46
  • Thanks mate. Setting a var in the sublass and doing label.strockedText = text directly from my VC did the trick for me. I didn't new this willSet method. Well thanks to you @roher – iji Nov 13 '16 at 19:26
1

Update to Swift 5

This answer is built on Anandnimje and J.Doe answers, and is meant to update and streamline it to make the usage clearer and simpler.

Simply use these two functions:

func outline(string:String, font:String, size:CGFloat, outlineSize:Float, textColor:UIColor, outlineColor:UIColor) -> NSMutableAttributedString {
    return NSMutableAttributedString(string:string,
                                     attributes: outlineAttributes(font: UIFont(name: font, size: size)!,
                                                        outlineSize: outlineSize, textColor: textColor, outlineColor: outlineColor))
}

func outlineAttributes(font: UIFont, outlineSize: Float, textColor: UIColor, outlineColor: UIColor) -> [NSAttributedString.Key: Any]{
    return [
        NSAttributedString.Key.strokeColor : outlineColor,
        NSAttributedString.Key.foregroundColor : textColor,
        NSAttributedString.Key.strokeWidth : -outlineSize,
        NSAttributedString.Key.font : font
    ]
}

Then use outline with your labels as the following:

label.attributedText = outline(string: "Label Text", font: "HelveticaNeue", size: 14, outlineSize: 4, textColor: .white, outlineColor: .black)
Ibrahim
  • 6,006
  • 3
  • 39
  • 50
0

Below is what I used in my App written in Swift 4.1

Swift 4.x

let strokeTextAttributes: [NSAttributedStringKey: Any] = [
    NSAttributedStringKey.strokeColor: UIColor.black,
    NSAttributedStringKey.foregroundColor : UIColor.white,
    NSAttributedStringKey.strokeWidth : -3.0,
    NSAttributedStringKey.font : UIFont.boldSystemFont(ofSize: 18)
]
fnisi
  • 1,181
  • 1
  • 14
  • 24
-2

Your code works for me if I set the type of the attributes dictionary, like this:

let strokeTextAttributes: [String: Any] = [
  // etc...
]

Maybe that's all your missing?

ganzogo
  • 2,516
  • 24
  • 36