Line Spacing for UILabel with a single line of text
Asked Answered
I

5

19

Is it expected that a multi-line UILabel with a custom lineSpacing attribute include that line spacing even when the label's text fits on one line?

Here is my label:

let label = UILabel()
label.numberOfLines = 4
var paragraph = NSMutableParagraphStyle()
paragraph.lineSpacing = 5
paragraph.lineBreakMode = .ByTruncatingTail
label.attributedText = NSAttributedString(string: "Some short text", attributes: [NSParagraphStyleAttributeName: paragraph])

And here is how it is laid out. Note the additional spacing below the text.

enter image description here

For comparison:

enter image description here

What's strange is the lack of consistency. When the label extends to a second line, the bottom line no longer includes this additional spacing:

enter image description here

Is there a way to remove this line spacing when there is a single line of text? Or some other way to enforce some consistency so I can at least account for it?

Update

The baseline calculation also seems broken. When attempting to align a view (here, the red box) with the label's baseline, multi-line labels are partially covered.

enter image description here enter image description here

Indiscipline answered 29/8, 2015 at 22:5 Comment(4)
Are you using a custom font?Terraqueous
@Terraqueous Yes I am. Specifically, various Gotham variants.Indiscipline
Have you tried the same tests with the system font?Peebles
FWIW i've verified that this happens even with a system font. And it can happen as long as attributes in a UILabel as long as the text attributes change somewhere in the string.Lotz
T
3

Since you said you were using a custom font, my best guess based on prior experience is that the root cause of that issue that you seeing lies somewhere inside of the custom font itself. Whenever I am given a custom font by a client, 90% of the time, something is "wrong" with the actual font metrics (as interpreted by Apple's internal font rendering subsystem, even though it might render correctly somewhere else).

The good news is that this is fixable, but it requires rebuilding the font with new metrics, which is usually a trial/error affair. You might also need to check to see if the license you have for the font will allow such a thing (if it even matters).

That being said, these are some resources to questions that I keep around for this exact scenario whenever I start a new project:

Here's a similar question to yours with the assumption that this is a custom font issue: "Custom UIFont baseline shifted". This question deals with this issue in a UIButton "UIButton custom font vertical alignment", but both of these questions end up at the answer to this question "Custom installed font not displayed correctly in UILabel".

I have a personal testbed app for custom fonts now that I use whenever I am first given a custom font. This allows me to test the font in isolation for each rebuild iteration to make sure it's perfectly rendering. Make sure to test your changes in various font sizes and even in additional languages (yes, lots of permutations). I have had issues specifically with Thai and Chinese when using custom fonts as their ascenders extend very close to the edge of the bounding box for a UILabel. The testbed that I've created for myself includes the font rendered in basic UILabels in various sizes and various languages in various sizes (since like I said, I've had a bad experience in the past with custom fonts in certain languages that rendered fine in Roman characters).

If someone has a better solution to this, I'd love to hear it as I run into this issue with custom fonts almost every time. This is my workflow for nipping the issue in the bud before we start compensating for the font's rendering issues during layout or using individual attributed string adjustments. I'm not font expert, I'm just a guy who likes fonts to render like the built-in fonts (especially when using auto layout).

Terraqueous answered 11/11, 2015 at 22:53 Comment(2)
Thanks for this. I would love to see your font testing suite open sourced! Thanks again.Indiscipline
I'm seeing the issue happen with the system font so it's not specific to custom fonts.Ceceliacecil
A
2

You can calculate the number of lines and set lineSpacing to 0 if there's only one line.

But there might be a better solution.

Autoharp answered 9/11, 2015 at 9:29 Comment(1)
This seems reasonable, I'd probably implement it from my parent view's layoutSubviews. FWIW I've worked extensively with iOS's various text APIs and I remember that NSParagraphStyle behaves extremely oddly in UILabel.Chevy
B
2
paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping 

can avoid this issue when text is multiline.

explicitly setting the font with with fontName [UIFont fontWithName:@"PingFangSC-Regular" size:14] , instead of using [UIFont systemFontOfSize:14] can avoid the issue when text is single line.

Hope this is helpful for you!

Beem answered 14/7, 2016 at 6:10 Comment(1)
The original question is about unwanted line spacing in a single line of text within a UILabel. The issue as described in the question does not exhibit itself in multiple lines of text so I can't see how this answers the original question.Ceceliacecil
N
1

This is def. a issue for UILabel. It happens for custom as well as the system fonts.

If you can use a UITextView, go with that. The UITextView has no problems with single or multi line text line-spacing and behaves correctly (single line = no line spacing).
This way you can also avoid creating a custom line count func/ext.

Nap answered 29/4, 2019 at 7:40 Comment(0)
H
-1

Yes, the lineSpacing is applied regardless of how many lines are in the label. If you're using autolayout, you can work around this by constraining your label's baseline to its parent or sibling views (as appropriate), instead of the label's top edge aligned to the parent or sibling's top. (This assumes, however, that your label's background color is the same as the color of its parent view; otherwise, you'll see the extra line spacing appear in the background color.

Another thing you can do (and this is probably preferable, now that I think about it) is to set a paragraphSpacing attribute of 0 as well. That should negate the lineSpacing for the last line in the label, regardless of how many lines you have.

Hose answered 29/8, 2015 at 22:27 Comment(4)
paragraphSpacing has no effect unless there are multiple paragraphs of text, which makes sense (unfortunately). And I'm not sure what you're getting at with the baseline alignment?Indiscipline
I understand now - you are suggesting that I use the label's baseline rather than bottom since it will be consistent in both cases. Unfortunately it makes no difference in practice.Indiscipline
Just double checked - in fact, when aligned with the label's baseline, the view actually overlaps the text when multiple lines are in use.Indiscipline
"... the lineSpacing is applied regardless of how many lines are in the label." This is not correct. As the original question demonstrates the last line in a multi-line text does not have space after it but a single-line of text does have space after it. Seems like a bug in UILabel or NSMutableParagraphStyle to me. I can't see how this is intended behaviour.Ceceliacecil

© 2022 - 2024 — McMap. All rights reserved.