UILabel created using Auto Layout does not show attributes for NSMutableAttributedString

306 views Asked by At

I have a UILabel object, calloutLabel that is created using programmatic auto layout:

- (void)setupCalloutLabel
{
    UILabel *calloutLabel = [UILabel newAutoLayoutView];
    calloutLabel.backgroundColor = [UIColor clearColor];
    calloutLabel.textAlignment = NSTextAlignmentCenter;
    calloutLabel.numberOfLines = 2;
    _calloutLabel = calloutLabel;
    [self addSubview:calloutLabel];

    NSNumber *padding = @(10.0f);
    NSNumber *calloutLabelHeight = @(132.0f);
    NSDictionary *calloutLabelMetrics = NSDictionaryOfVariableBindings(padding, calloutLabelHeight);

    UIImageView *logoImageView = _logoImageView;
    NSDictionary *ecalloutLabelViews = NSDictionaryOfVariableBindings(calloutLabel, logoImageView);

    NSLayoutConstraint *calloutLabelHorizontalConstraint = [NSLayoutConstraint constraintWithItem:calloutLabel
                                                                                        attribute:NSLayoutAttributeWidth
                                                                                        relatedBy:NSLayoutRelationEqual
                                                                                           toItem:self
                                                                                        attribute:NSLayoutAttributeWidth
                                                                                       multiplier:1.0f
                                                                                         constant:0.0f];

    NSArray *calloutLabelVerticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[logoImageView]-(padding)-[calloutLabel(calloutLabelHeight)]"
                                                                                       options:NSLayoutFormatAlignAllCenterX
                                                                                       metrics:calloutLabelMetrics
                                                                                         views:ecalloutLabelViews];

    [self addConstraint:calloutLabelHorizontalConstraint];
    [self addConstraints:calloutLabelVerticalConstraints];
    [self setNeedsLayout];
    [self layoutIfNeeded];
}

Later in the code, I dynamically updated _calloutLabel.attributedText with the following:

    NSString *calloutString = offer[kAPIAttributeOffersOfferCallout];
    NSMutableAttributedString *calloutAttributedString = [[NSMutableAttributedString alloc] initWithString:calloutString];

    NSString *firstLine = nil;
    NSScanner *calloutScanner = [NSScanner scannerWithString:calloutString];
    [calloutScanner scanUpToString:@"\n" intoString:&firstLine];
    NSRange firstLineRange = NSRangeFromString(firstLine);
    NSDictionary *firstLineAttributes = @{NSFontAttributeName : [UIFont fontWithName:kFontNameSemibold size:48.0f],
                                          NSForegroundColorAttributeName : [UIColor colorWithHex:kColorLightBlue andAlpha:1.0f]};
    [calloutAttributedString addAttributes:firstLineAttributes range:firstLineRange];

    NSString *secondLine = nil;
    [calloutScanner scanUpToString:@"" intoString:&secondLine];
    NSRange secondLineRange = NSRangeFromString(secondLine);
    NSDictionary *secondLineAttributes = @{NSFontAttributeName :[UIFont fontWithName:kFontNameSemibold size:30.0f],
                                           NSForegroundColorAttributeName : [UIColor colorWithHex:kColorLightBlue andAlpha:1.0f]};
    [calloutAttributedString addAttributes:secondLineAttributes range:secondLineRange];

    _calloutLabel.attributedText = calloutAttributedString;

Here's what it should look like: enter image description here

Here's what it actually looks like: enter image description here

Am I making a mistake somewhere?

Thank you!

1

There are 1 answers

3
Fabio Ritrovato On BEST ANSWER

NSRangeFromString is used to create a range out of a string representation of it (e.g. @"{1,5}"), not to get the range of the scanned string.

What you actually want to do is make a range up to the scanner location, so

NSRange firstLineRange = NSMakeRange(0, calloutScanner.scanLocation);

For the second location, you could probably skip the scanning, just use the length of the string

NSRange secondLineRange = NSMakeRange(firstLineRange.length + 1, [calloutString length] - firstLineRange.length - 1);