9

I've got a UILabel and I want to make the line spacing less than 0 (so the text moves closer together rather than further away). What am I doing wrong?

 UIFont* customFont = [UIFont fontWithName:@"BebasNeue" size:70]; NSString * text = @"Their \nIdeas"; NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:text]; NSMutableParagraphStyle *paragrahStyle = [[NSMutableParagraphStyle alloc] init]; paragrahStyle.lineSpacing = -30; [attributedString addAttribute:NSParagraphStyleAttributeName value:paragrahStyle range:NSMakeRange(0, [text length])]; UILabel *lbl1 = [[UILabel alloc] init]; lbl1.frame = CGRectMake(120, 0, viewWidth, 300); lbl1.backgroundColor = [UIColor clearColor]; lbl1.textColor = grayColor; lbl1.numberOfLines = 2; lbl1.attributedText = attributedString; lbl1.userInteractionEnabled = NO; lbl1.font = customFont; [view addSubview:lbl1]; [lbl1 setTransform:CGAffineTransformMakeRotation(0.35)]; 
5
  • What does it look like with your code here? Commented Apr 9, 2014 at 16:02
  • You don't really need a label here, so what I would do in your place is make a custom UIView where I draw the text myself. That way, you can put the lines wherever you like. Commented Apr 9, 2014 at 17:00
  • @matt I was about to suggest the same thing. CoreText is probably the way to go here. Commented Apr 9, 2014 at 17:03
  • @Fogmeister No need for Core Text. Just draw two NSAttributedStrings in the place where you want them. Or, to be snazzier, use TextKit. Commented Apr 9, 2014 at 17:06
  • @matt ah, I meant TextKit :D Got the name mixed up :) Commented Apr 9, 2014 at 17:07

5 Answers 5

24
NSMutableAttributedString* attrString = [[NSMutableAttributedString alloc] initWithString:labelText]; NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init]; CGFloat minMaxLineHeight = (font.pointSize - font.ascender + font.capHeight); NSNumber *offset = @(font.capHeight - font.ascender); NSRange range = NSMakeRange(0, labelText.length); [style setMinimumLineHeight:minMaxLineHeight]; [style setMaximumLineHeight:minMaxLineHeight]; if (isCentered) { [style setAlignment:NSTextAlignmentCenter]; } [attrString addAttribute:NSParagraphStyleAttributeName value:style range:range]; [attrString addAttribute:NSBaselineOffsetAttributeName value:offset range:range]; 

This should get you near zero spacing on the text and should be safe to use with any font type and size.

Sign up to request clarification or add additional context in comments.

4 Comments

Lifesaver! Finally someone with the answer I wanted!
Can do even simpler: just set style setMaximumLineHeight to font.ascender and dont need to use NSBaselineOffset then
@NickKovalsky's comment to set max line height to the font.ascender WORKS and is much SIMPLER. Thanks!
@ericMurphey Can you take a look at this question/link and see if you can help? Appreciate it! stackoverflow.com/questions/58069302/…
7

Please see the following documentation from Apple setLineSpacing - NSMutableParagraphStyle , value must not be negative

setLineSpacing: Sets the distance in points added between lines within the paragraph to aFloat.

 - (void)setLineSpacing:(CGFloat)aFloat 

Discussion

This value must be nonnegative.

There are also methods related to the minimum and maximum height for lines… probably setting line space to 0 and modifying the height could help you to achieve the effect you want-

1 Comment

Well I've got a font that is so broken that I actually need negative line spacing but I can't get it…
7

Building off of Eric Murphey's answer, I've created an extension in Swift 4 syntax.

extension UILabel{ public func zeroLineSpace(){ let s = NSMutableAttributedString(string: self.text!) let style = NSMutableParagraphStyle() let lineHeight = self.font.pointSize - self.font.ascender + self.font.capHeight let offset = self.font.capHeight - self.font.ascender let range = NSMakeRange(0, self.text!.count) style.maximumLineHeight = lineHeight style.minimumLineHeight = lineHeight style.alignment = self.textAlignment s.addAttribute(.paragraphStyle, value: style, range: range) s.addAttribute(.baselineOffset, value: offset, range: range) self.attributedText = s } } 

Simply call it like so

myUiLabel.zeroLineSpace() 

2 Comments

This works out great but with Xcode 11 and iOS 13 this doesn't seem to work anymore. I'm using this inside a collection view and when I scroll my labels text is not centered inside the label itself. Any help would be great!
Please don’t use force unwrapping and single letter symbol names.
3

Just a minor tweak to make things more configurable.

extension UILabel { public func setLineHeight(lineHeight: CGFloat, textAlignment: NSTextAlignment ) { guard let text = self.text else { return } let attributeString = NSMutableAttributedString(string: text) let styleLineHeight = self.font.pointSize - self.font.ascender + self.font.capHeight + lineHeight let style = NSMutableParagraphStyle() style.alignment = textAlignment style.maximumLineHeight = styleLineHeight style.minimumLineHeight = styleLineHeight let offset = self.font.capHeight - self.font.ascender + lineHeight * 0.5 let range = NSMakeRange(0, text.count) attributeString.addAttribute(.paragraphStyle, value: style, range: range) attributeString.addAttribute(.baselineOffset, value: offset, range: range) self.attributedText = attributeString } } 

Comments

0

I cleaned up Christ Stillwell's answer a little bit:

 extension UILabel { public func zeroLineSpace() { guard let text = self.text else { return } let attributedString = NSMutableAttributedString(string: text) let style = NSMutableParagraphStyle() let lineHeight = self.font.pointSize - self.font.ascender + self.font.capHeight let offset = self.font.capHeight - self.font.ascender let range = NSRange(location: 0, length: attributedString.length) style.maximumLineHeight = lineHeight style.minimumLineHeight = lineHeight style.alignment = self.textAlignment attributedString.addAttribute(.paragraphStyle, value: style, range: range) attributedString.addAttribute(.baselineOffset, value: offset, range: range) self.attributedText = attributedString } } 

1 Comment

Great improvement for not using force unwrapping and single letter symbol names.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.