7

I've looked at ~10 questions on SO and am still coming up short.

I have a multiline UILabel (created in Interface Builder, numberOfLines set to 0) which renders normally like this:

enter image description here

I want to be underline "Terms of Service" and "Privacy Policy", so I added this code:

NSString *text = self.agreement.text;
NSMutableAttributedString *aString = [[NSMutableAttributedString alloc] initWithString:text];

NSRange privacyRange = [text rangeOfString:@"privacy policy" options:NSCaseInsensitiveSearch];
[aString addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:privacyRange];

NSRange tosRange = [text rangeOfString:@"terms of service" options:NSCaseInsensitiveSearch];
[aString addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:tosRange];

self.agreement.attributedText = aString;

But the result looks like this:

enter image description here

What do I need to do so both lines appear, with the appropriate ranges underlined?

Also, I'd prefer not to use a 3rd Party Library like OHAttributedLabel or TTTAttributedLabel since this is the only place in my app where I need to underline a piece of text.

What I've Tried

  • calling sizeToFit after setting the attributed text
  • using a UITextView instead. Both lines rendered correctly but I lost the center alignment.
  • resetting numberOfLines and lineBreakMode in code

Sascha asked me to upload two screenshots with the background colors set to something other than clear. Oddly enough, everything shows up as expected! Not sure what to make of this or what this is telling us.

enter image description here

djibouti33
  • 12,102
  • 9
  • 83
  • 116
  • For testing purposes, give the label a height that's seemingly larger than necessary. Is the first line still clipped? – bilobatum Mar 06 '14 at 22:59
  • If I adjust the height in IB, the entire label disappears when running the app. If I adjust the label's frame in code in `viewDidLoad`, I just get one line with two underlined ranges. – djibouti33 Mar 06 '14 at 23:06
  • And all this strange behavior occurs only if you underline? – bilobatum Mar 06 '14 at 23:09
  • Due to Apple bug (I saw on SO that it suppose to be fixed on 7.1), I suggest that for now you will just use 2 separate UILabels, that will be the quickest solution. I wasted many hours on it also.. – tsafrir Mar 06 '14 at 23:10
  • @bilobatum, oddly enough if I set the attributed strings to a different color instead of underline, everything shows up fine. If one is a color and one is an underline, I only see one line of text. Due to tsafrir's advice, perhaps I'll just use two labels, or go ahead with a color change instead of an underline. – djibouti33 Mar 06 '14 at 23:24
  • Can you please upload 2 screenshots, where the labels have a non-clear background-color? :-) – Sascha Manuel Hameister Mar 07 '14 at 00:16
  • @SaschaHameister, just added the screenshots. Very weird that applying a non-clear background-color renders both lines. What does this suggest? – djibouti33 Mar 07 '14 at 16:20
  • This sounds really strange. I just wanted to know, how the frame looks like. As workaround you might use a UIColor nearly transparent. – Sascha Manuel Hameister Mar 07 '14 at 17:12

2 Answers2

3
  1. First create attributed text as you did:

    NSString *text = self.agreement.text;
    NSMutableAttributedString *aString = [[NSMutableAttributedString alloc] initWithString:text];
    
    NSRange privacyRange = [text rangeOfString:@"privacy policy" options:NSCaseInsensitiveSearch];
    [aString addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:privacyRange];
    
    NSRange tosRange = [text rangeOfString:@"terms of service" options:NSCaseInsensitiveSearch];
    [aString addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:tosRange];
    
  2. Assign font you'd like to use to your attributed string:

    [aString addAttribute:NSFontAttributeName value:self.agreement.font range:(NSRange){0, aString.length}];
    
    self.agreement.attributedText = aString;
    
  3. Define your label to be multiline:

    self.agreement.numberOfLines = 0;
    self.agreement.lineBreakMode = NSLineBreakByWordWrapping;
    
  4. Estimate your label size:

    CGRect myLabelRect = [aString boundingRectWithSize:CGSizeMake(self.view.frame.size.width, INT_MAX)
                                               options:NSStringDrawingUsesLineFragmentOrigin
                                               context:nil];
    
  5. Use estimated size when adding label to view:

    self.agreement.frame = CGRectMake(self.view.frame.size.width / 2 - myLabelRect.size.width / 2,
                                      0,
                                      myLabelRect.size.width,
                                      myLabelRect.size.height);
    [self.view addSubview:self.agreement];
    
Misha
  • 5,260
  • 6
  • 35
  • 63
0

So yesterday, based on tsafrir's comments (iOS 7 bug, should be fixed in 7.1), I broke the two lines into two labels and moved on.

Then, SashaHameister recommended I see what happens when I apply a non-clear background-color. So I deleted the top label, added the text to the second label so it was two lines, change the background-color, and both lines rendered fine. I thought that was the solution (even though it wouldn't work because I needed a clear background).

After that, I tested changing it back to clear, and it still worked for me. It turns out it had something to do with the size of my label. My two line label had a height of ~75, way more than necessary for a two line label at 11pt font. Because of the adjustments I made yesterday (breaking the lines up to two labels), when I copy and pasted the first label's text into the second, the height only ended up being 48px, and that renders just fine.

I still have no idea why this makes such an impact, but if you're having the same problem, chances are your label's height is larger than it needs to be. Try reducing it as much as possible and get it as tight on the actual text as you can.

djibouti33
  • 12,102
  • 9
  • 83
  • 116
  • This seems like a layout issue. You're not using Auto Layout? – bilobatum Mar 08 '14 at 00:25
  • I am struggling with nearly the exact issue currently. I tried resizing the label and sure enough the first line is now rendered. What a strange behavior! Resizing is not a perfect solution though. The UILabel is in a `UITableViewCell`. Each cell contains unique data. For example if I have a 3 line UILabel I can size it so all 3 lines show, but if the next cell in my table only has two lines worth of text the first line will be cut off…. – Ben Mar 09 '14 at 00:02
  • I spent a few hours attempting a work around and gave up. I just changed the UILabel to a UITextView and turned of the ability to edit and select. Works like a champ – Ben Mar 09 '14 at 00:53