25

A simple test that is failed: Make a new project with just one subview (UITextView) and put the following in:

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    paragraphStyle.lineHeightMultiple = 50.f;
    paragraphStyle.lineSpacing = 100.f;
    paragraphStyle.minimumLineHeight = 200.f;
    paragraphStyle.maximumLineHeight = 500.f;

    UIFont *font = [UIFont fontWithName:@"AmericanTypewriter" size:24.f];

    self.textView.attributedText = [[NSAttributedString alloc] initWithString:
    @"This is a test.\n Will I pass?" attributes:
    @{NSParagraphStyleAttributeName : paragraphStyle, NSFontAttributeName : font}];
}

Line spacing is the same as if the attribute were not there. Has anything got this to work successfully? I put in ridiculous numbers just to show that it won't change...

borrrden
  • 33,256
  • 8
  • 74
  • 109
  • I'm having the same issue..have you figured out a solution? – Snowman Oct 02 '12 at 16:04
  • @mohabitar The solution appears to be wait until Apple fixes it. An alternative would be to use DTCoreText and implement your own selection. Most of the selection code is available in an Apple sample called SimpleTextInput (it is disabled by default, but it is there). – borrrden Oct 02 '12 at 23:33

6 Answers6

24

This is a bug in NSHTMLWriter which is the private class which UITextView uses to convert attributedText into HTML. Internally it displays this HTML via a UIWebDocumentView. Read more on the inner workings of UITextView in my writeup here: http://www.cocoanetics.com/2012/12/uitextview-caught-with-trousers-down/

The problem comes from an easy to miss speciality in the font CSS shorthand. If you specify a pixel size with the font shorthand then this sets BOTH the font-size as well as the line-height. Since NSHTMLWriter puts the font AFTER the line-height this causes the line-height to be cancelled out by the font size.

See here for my Radar which includes the full analysis of the bug: http://www.cocoanetics.com/2012/12/radar-uitextview-ignores-minimummaximum-line-height-in-attributed-string/

I suggest you file a bug report as well and mention my Radar #12863734.

Cocoanetics
  • 8,171
  • 2
  • 30
  • 57
  • I would love to, but actually I have never been able to log into the bug report website...I emailed to complain but never got a response :-S. This is interesting though! – borrrden Dec 16 '12 at 23:24
  • You should telephone DTS, they can help you there. Phone number depending on your country on the website. – Cocoanetics Dec 17 '12 at 06:05
  • 1
    Please consider posting follow up if Apple ever responds. Thanks for this! – jaredsinclair Dec 24 '12 at 04:47
  • @Cocoanetics In iOS 7, I'm having a similar, possibly related problem here: http://stackoverflow.com/questions/19232006/uilabel-applying-line-break-mode-to-only-a-portion-of-the-text – Aaron Brager Oct 07 '13 at 18:58
23

I don't know if this is enough for your purposes but I could adjust the line spacing by setting the minimum and maximum line height. Furthermore to use a font I put it into the font property of the text view rather than passing it as the value of NSFontAttributeName in the attributes dictionary. (Maybe this part is not (well) documented?)

About your attributes

lineSpacing is calculated from the bottom of the line to the bottom of the upper line and that space is constrained to values between minimumLineHeight and miximumLineHeight. What I am trying to say is that maybe some values in your attributes are cancelling or overriding others.

Also if you need to just adjust the spacing between line you probably don't need to use paragraphStyle.lineHeightMultiple :)

The code

This worked for me:

NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.minimumLineHeight = 35.f;
paragraphStyle.maximumLineHeight = 35.f;

UIFont *font = [UIFont fontWithName:@"AmericanTypewriter" size:18.f];
NSString *string = @"This is a test.\nWill I pass?\n日本語のもじもあるEnglish\nEnglish y Español";
NSDictionary *attributtes = @{
    NSParagraphStyleAttributeName : paragraphStyle,
};
self.textView.font = font;
self.textView.attributedText = [[NSAttributedString alloc] initWithString:string
                                 attributes:attributtes];

Additional Notes

There seems to be a situation with Japanese/Chinesse and maybe other characters mixed with alphabet characters in the same line. It will make that line to have a bigger leading to solve that you need to set up the minimum and maximum line height as I did. You can see the problem when rendering my example without attributes.

nacho4d
  • 43,720
  • 45
  • 157
  • 240
  • This might be enough. I'll look into it when I go back to the office. – borrrden Oct 07 '12 at 15:22
  • Thought I should comment that this won't work since I will mix fonts in the same label :-S (Italic, regular, etc). – borrrden Dec 03 '12 at 03:47
  • This approach should work as long as you use the same font size. Italics and regulars will result in the same line height. – nacho4d Dec 03 '12 at 05:04
  • 2
    When I set the font via NSFontAttributeName, the line spacing starts to be ignored again..that's the big problem (there is no other way to mix styles in the same label). http://stackoverflow.com/questions/13298748/using-attributedtext-nsattributedstring-on-a-uitextview-on-ios6-only-works-wit?rq=1 – borrrden Dec 03 '12 at 05:08
  • @borrrden - did you ever find a solution for this I'm wondering? – Ser Pounce Jun 20 '14 at 05:55
9

Setting maximumLineHeight seems to resolve this issue for me;

CGFloat fontSize = 22.f;
titleLabel.font = [UIFont boldSystemFontOfSize:fontSize];
NSMutableParagraphStyle *paragraphStyle = [[[NSMutableParagraphStyle  alloc] init] autorelease];
paragraphStyle.maximumLineHeight = fontSize/2;
titleLabel.attributedText = [[[NSAttributedString alloc]
                              initWithString:@"This is a test.\nWill I pass?"
                              attributes: @{ NSParagraphStyleAttributeName : paragraphStyle,
                                             NSFontAttributeName : titleLabel.font}]
                             autorelease];

overlapping lines

Henrik Hartz
  • 3,677
  • 1
  • 27
  • 28
5

For this particular string you need to set paragraphSpacing instead. What's about lineSpacing, I believe it's just not supported yet on iOS.

pronvit
  • 4,169
  • 1
  • 18
  • 27
  • Good tip about paragraph spacing +1. However, I am looking to stop using UIWebView...so until UITextView can do CSS line-height I can't... – borrrden Sep 24 '12 at 10:05
0

As nacho4d answered, in iOS 6 you need to use minimumLineHeight and maximumLineHeight and set font directly in UITextView, not in NSAttributedString as line height in that case will be overridden.

Please note that when you set font in UITextView, the "editable" property of UITextView should be set to YES, in other case attributed text would not be affected.

These issues are present only in iOS 6. In iOS 7 and above everything is ok;

Valeriy
  • 71
  • 4
0

In my case, none of the paragraph styling was working. The fix was to set the attributed text on the label AFTER doing any frame adjustments on the label. :)

Erik Villegas
  • 954
  • 13
  • 29