Is there anyway to change the character spacing (track) on UILabel text using Interface Builder? If not, is there a way to do it programmatically on an existing UILabel that was already created with attributed text?
-
1I'm 99% sure Xcode 6 does not support this. – Drux Dec 17 '14 at 22:20
-
3@Drux i'm 99% sure Xcode 6 can do IBDesignables – ninjaneer Aug 12 '15 at 01:34
14 Answers
I know it's not an Interface Builder solution, but you can create a UILabel
extension and then add spacing to any UILabel
you want:
extension UILabel {
func addCharacterSpacing(kernValue: Double = 1.15) {
guard let text = text, !text.isEmpty else { return }
let string = NSMutableAttributedString(string: text)
string.addAttribute(NSAttributedString.Key.kern, value: kernValue, range: NSRange(location: 0, length: string.length - 1))
attributedText = string
}
}
Consider changing the default kernValue
from 1.15
to something that works better with your design.
When implementing always add character spacing after setting the text value:
myLabel.text = "We used to be so close"
myLabel.addCharacterSpacing()
If you plan to have different spacing at different places in the app, you can override the default kern value:
myLabelWithSpecialNeeds.addCharacterSpacing(kernValue: 1.3)
This solution overrides any other attributes you might have on your UILabel
's attributedText
.

- 13,044
- 8
- 95
- 91
-
-
@Priyal, there is a 1.15 spacing value in there... just change it to a bigger number if you want more spacing – budiDino May 03 '17 at 14:51
-
@budidino as I can infer from example you have increased spacing between words but I want to change character spacing, ie. between We & user or used & to.... but I want to manage spacing between 'W' and 'e' of We, 'u', 's','e' and 'r' of user. Is it possible ? – Priyal May 03 '17 at 14:59
-
-
2Very nice answer! Little addition: you may change the if clause to `if let textString = text, textString.length > 0` to **catch index out of bounds** when the string is "" (empty). – inf1783 Jul 31 '17 at 09:06
-
I think this solution overwrites any existing `attributedText` properties – tomblah Jan 10 '20 at 03:24
-
Ended up using this for now to get existing attributed text and modify to add character spacing:
let attributedString = discoveryTitle.attributedText as NSMutableAttributedString
attributedString.addAttribute(NSKernAttributeName, value: 1.0, range: NSMakeRange(0, attributedString.length))
discoveryTitle.attributedText = attributedString
Swift 3:
let attributedString = NSMutableAttributedString(string: discoveryTitle.text)
attributedString.addAttribute(NSKernAttributeName, value: CGFloat(1.0), range: NSRange(location: 0, length: attributedString.length))
discoveryTitle.attributedText = attributedString
Using NSRange instead of NSMakeRange works in Swift 3.
-
9+1. Awesome answer. If your text must remain centred, apply the kerning to all but the last character, i.e. change `NSMakeRange(0, attributedString.length)` to `NSMakeRange(0, attributedString.length - 1)`. [Source](http://stackoverflow.com/a/23743928/1305067) – paulvs Jul 03 '16 at 22:22
-
@paulvs is correct. You also need to validate the empty string to avoid crash. Simply add `max(0, attributedString.length - 1)` will help. – nahung89 Oct 08 '21 at 05:35
For completely static text, like the header of a view or especially the launchScreen, you can insert letters that take up a tiny amount of width (e.g. the 'l' character) with 0 opacity
. Alternatively set its color to the same as background.
I am aware of the fact, that is not the prettiest solution, but it is the only solution that works without writing any code and does the job - until you can do it by specifying the attributes in Xcode.
Edit / Additional idea: To make your spacing even more variable you can change the font size of the filling charachters in between. (Thanks to @mohamede1945 for that idea)

- 55,258
- 23
- 97
- 137
-
-
Thanks, the idea just popped into my head and i had to laugh myself because it is quite a cheesy solution ^^ – luk2302 Mar 25 '15 at 22:58
-
1Awesome solution! :) you can even control the width with the font size of the '|' character. All you need is just create one and copy/paste it :) – mohamede1945 Jun 17 '15 at 02:01
-
3@mohamede1945 nice idea, before i actually read you comment and read through my answer again (was given quite a while back) I also got the idea to maybe change the font size as well - then read your comment... if two people independently come up with the same idea, it has to be good ;) – luk2302 Jun 17 '15 at 08:05
-
Yes definitely and really thank you for the original idea. You saved me a lot of time trying to do NSAttributedString in code. – mohamede1945 Jun 18 '15 at 02:24
-
5
-
2
-
2This is a really bad idea for accessibility. If you use this be sure to set the accessibility label to the real text. – Sami Samhuri Dec 14 '17 at 21:11
Swift 3.2 & Interface builder
extension UILabel {
@IBInspectable
var letterSpace: CGFloat {
set {
let attributedString: NSMutableAttributedString!
if let currentAttrString = attributedText {
attributedString = NSMutableAttributedString(attributedString: currentAttrString)
}
else {
attributedString = NSMutableAttributedString(string: text ?? "")
text = nil
}
attributedString.addAttribute(NSKernAttributeName,
value: newValue,
range: NSRange(location: 0, length: attributedString.length))
attributedText = attributedString
}
get {
if let currentLetterSpace = attributedText?.attribute(NSKernAttributeName, at: 0, effectiveRange: .none) as? CGFloat {
return currentLetterSpace
}
else {
return 0
}
}
}
}

- 1,758
- 19
- 18
-
2
-
-
Totally perfect way. I also added the same code for UILabel and UIButton and they also work. Just get text from titleLabel.text and titleLabel.attributedText for UIButton – Okhan Okbay Oct 13 '20 at 23:35
-
Great solution, couple of code updates for things that have been updated in later versions of Xcode, but Xcode handles all the fixes for you. Thanks! – Chris Jan 03 '22 at 09:53
Swift 5 and higher
extension UILabel {
func setTextSpacingBy(value: Double) {
if let textString = self.text {
let attributedString = NSMutableAttributedString(string: textString)
attributedString.addAttribute(NSKernAttributeName, value: value, range: NSRange(location: 0, length: attributedString.length - 1))
attributedText = attributedString
}
}
}

- 896
- 11
- 16
-
1@craft he edit his answer, before there was no default value. I'll edit mine too, thx. – FredFlinstone Nov 26 '20 at 10:02
try this!!
create CustomLabel class
@interface CustomLabel : UILabel
@property (assign, nonatomic) CGFloat myLineSpacing;
@end
@implementation CustomLabel
- (void)setMyLineSpacing:(CGFloat)myLineSpacing {
_myLineSpacing = myLineSpacing;
self.text = self.text;
}
- (void)setText:(NSString *)text {
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineSpacing = _myLineSpacing;
paragraphStyle.alignment = self.textAlignment;
NSDictionary *attributes = @{NSParagraphStyleAttributeName: paragraphStyle};
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text
attributes:attributes];
self.attributedText = attributedText;
}
and set runtime attribute
Note this is actually line spacing (also called leading .. in the very old days (pre-digital) you'd put lead (the metal) between lines to increase the gap between lines. For spacing between letters, that is called kerning .. here's how to do kerning https://stackoverflow.com/a/21141156/294884

- 1
- 1

- 3,111
- 1
- 21
- 34
Why all of you are defining NSMUTABLEAttributedString. You don't have to set range explicitly. It makes emojis looks weird sometimes. This is my solution, tested in Swift 4.
extension UILabel {
func addCharactersSpacing(_ value: CGFloat = 1.15) {
if let textString = text {
let attrs: [NSAttributedStringKey : Any] = [.kern: value]
attributedText = NSAttributedString(string: textString, attributes: attrs)
}
}
}

- 5,977
- 3
- 50
- 55
-
If you don't specify the range, center and right aligned texts will look off the mark because there will be added spacing after the last character. I might be completely wrong though :) – budiDino Nov 06 '17 at 11:58
SWIFT 4 UILabel extension:
import UIKit
extension UILabel {
@IBInspectable
var letterSpace: CGFloat {
set {
let attributedString: NSMutableAttributedString!
if let currentAttrString = attributedText {
attributedString = NSMutableAttributedString(attributedString: currentAttrString)
} else {
attributedString = NSMutableAttributedString(string: text ?? "")
text = nil
}
attributedString.addAttribute(NSAttributedString.Key.kern,
value: newValue,
range: NSRange(location: 0, length: attributedString.length))
attributedText = attributedString
}
get {
if let currentLetterSpace = attributedText?.attribute(NSAttributedString.Key.kern, at: 0, effectiveRange: .none) as? CGFloat {
return currentLetterSpace
} else {
return 0
}
}
}
}

- 5,730
- 1
- 39
- 45
Here is a solution for Swift 4 that won't override existing text attributes:
extension UILabel {
/**
Add kerning to a UILabel's existing `attributedText`
- note: If `UILabel.attributedText` has not been set, the `UILabel.text`
value will be returned from `attributedText` by default
- note: This method must be called each time `UILabel.text` or
`UILabel.attributedText` has been set
- parameter kernValue: The value of the kerning to add
*/
func addKern(_ kernValue: CGFloat) {
guard let attributedText = attributedText,
attributedText.string.count > 0,
let fullRange = attributedText.string.range(of: attributedText.string) else {
return
}
let updatedText = NSMutableAttributedString(attributedString: attributedText)
updatedText.addAttributes([
.kern: kernValue
], range: NSRange(fullRange, in: attributedText.string))
self.attributedText = updatedText
}
}

- 39
- 1
You can use the following Swift 4 UILabel extension which considers both existing attributed text and plain text in order to do not override the existing settings:
import UIKit
extension UILabel {
func addCharacterSpacing(_ kernValue: Double = 1.30) {
guard let attributedString: NSMutableAttributedString = {
if let text = self.text, !text.isEmpty {
return NSMutableAttributedString(string: text)
} else if let attributedText = self.attributedText {
return NSMutableAttributedString(attributedString: attributedText)
}
return nil
}() else { return}
attributedString.addAttribute(
NSAttributedString.Key.kern,
value: kernValue,
range: NSRange(location: 0, length: attributedString.length)
)
self.attributedText = attributedString
}
}

- 1,358
- 1
- 16
- 43
Here is my code for letter spacing. Create custom label class and set letter spacing from storyboard. Swift 5.
import UIKit
class SpacingLabel: UILabel {
@IBInspectable
var letterSpacing: Double = 0
override public var text: String? {
didSet {
self.addCharacterSpacing(letterSpacing)
}
}
func addCharacterSpacing(_ kernValue: Double) {
if let labelText = text, labelText.count > 0 {
let attributedString = NSMutableAttributedString(string: labelText)
attributedString.addAttribute(NSAttributedString.Key.kern, value: kernValue, range: NSRange(location: 0, length: attributedString.length - 1))
attributedText = attributedString
}
}
}

- 3,749
- 1
- 20
- 34

- 31
- 2
-
Please note, you must call label.text = "some text" from code to make it work :)) – Yuri Bikovsky Jan 30 '21 at 12:37
Try this. It will add the character spacing you assign, either you set simple text or attributed text.
open class UHBCustomLabel : UILabel {
@IBInspectable open var characterSpacing:CGFloat = 1 {
didSet {
updateWithSpacing()
}
}
open override var text: String? {
set {
super.text = newValue
updateWithSpacing()
}
get {
return super.text
}
}
open override var attributedText: NSAttributedString? {
set {
super.attributedText = newValue
updateWithSpacing()
}
get {
return super.attributedText
}
}
func updateWithSpacing() {
let attributedString = self.attributedText == nil ? NSMutableAttributedString(string: self.text ?? "") : NSMutableAttributedString(attributedString: attributedText!)
attributedString.addAttribute(NSKernAttributeName, value: self.characterSpacing, range: NSRange(location: 0, length: attributedString.length))
super.attributedText = attributedString
}
}

- 1,203
- 13
- 15
Programming approach. (Try this, it should work for you)
Note: I tested in Swift 4
let label = UILabel()
let stringValue = "How to\ncontrol\nthe\nline spacing\nin UILabel"
let attrString = NSMutableAttributedString(string: stringValue)
var style = NSMutableParagraphStyle()
style.lineSpacing = 24 // change line spacing between paragraph like 36 or 48
style.minimumLineHeight = 20 // change line spacing between each line like 30 or 40
// Line spacing attribute
attrString.addAttribute(NSAttributedStringKey.paragraphStyle, value: style, range: NSRange(location: 0, length: stringValue.characters.count))
// Character spacing attribute
attrString.addAttribute(NSAttributedStringKey.kern, value: 2, range: NSMakeRange(0, attrString.length))
label.attributedText = attrString

- 77,632
- 48
- 245
- 261
Swift 5.3.1
extension UILabel {
func addCharacterSpacing(kernValue: Double = 1.15) {
if let labelText = text, labelText.count > 0 {
let attributedString = NSMutableAttributedString(string: labelText)
attributedString.addAttribute(NSAttributedString.Key.kern, value: kernValue, range: NSRange(location: 0, length: attributedString.length - 1))
attributedText = attributedString
}
}
}

- 857
- 1
- 11
- 25
-
-
1@craft 'NSAttributedStringKey' has been renamed to 'NSAttributedString.Key' – David Nov 26 '20 at 07:23