KalyanChakravarthy.net

home photos apps about

Using Attributed Strings on iOS

Tue 03 June 2014

Setting up Attributed string

Setting font, foreground color, etc on UILabel* for normal text is quite straight forward as all the attributes are set on the instance directly. For attributed text, all these properties have to be set explicitly on NSAttributedString instance as none of the text attributes from UILabel are applied.

This example creates a string and highlights a specific part by making it bold and changing the color to gray. The attributes are not applied to a string but a range of characters.

NSString *userName = @"Tex";
NSString *stringToHighlight = [NSString stringWithFormat:@"Hello there human. Are you %@ ?", userName];

// Set global fontsize on the string
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:stringToHighlight
                                                                               attributes:@{
                                                                                            NSFontAttributeName: [UIFont systemFontOfSize:14.0]
                                                                                            }];
// Compute the range of the string that needs a different font
NSRange *userNameRange = [stringToHighlight rangeOfString:userName];

// Apply new attributes for a specific range
[attrString setAttributes:@{
                            NSFontAttributeName:[UIFont boldSystemFontOfSize:14],
                            NSForegroundColorAttributeName:[UIColor grayColor]
                           }
                    range:userNameRange];

// Make UILabel use attributedString as source
UILabel *label = [[UILabel alloc] initWithFrame:self.view.frame];
label.attributedText = attrString;

Size and bounding box

Due to attributes being present inside the NSAttributedString, the methods to compute bounding box under constraints -sizeWithFont:constrainedToSize:lineBreakMode or just just size for attributes -sizeWithAttributes: no longer work. Instead we need to use this:

CGRect labelSizeRect = [_attributedString boundingRectWithSize:CGSizeMake(label.frame.size.width, 1000)
                                                   options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
                                                   context:nil];

CGSize labelSize = labelSizeRect.size;

The options in the call boundingRectWithSize are important as they determine the origin from which bounding rect should be computed.

  • NSStringDrawingUsesLineFragmentOrigin - uses the top left corner as origin rather than the baseline (which usually is center)
  • NSStringDrawingUsesFontLeading - font leading basically means line spacing. This flag indicates the call to make use of default line spacing specified by the font.