Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSAttributedString on multiline UILabel cutting off first line

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

like image 268
djibouti33 Avatar asked Mar 06 '14 22:03

djibouti33


1 Answers

  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];
    
like image 110
Misha Avatar answered Oct 20 '22 17:10

Misha