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
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)
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.
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
}
}
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
}
}
}
}
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) {
if let labelText = text, labelText.count > 0 {
let attributedString = NSMutableAttributedString(string: labelText)
attributedString.addAttribute(NSAttributedStringKey.kern, value: kernValue, range: NSRange(location: 0, length: attributedString.length - 1))
attributedText = attributedString
}
}
}
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
.
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