lakshmen
lakshmen

Reputation: 29064

Setting italic text for a certain portion of the text in iOS

I am using TTTAttributedLabel(https://github.com/mattt/TTTAttributedLabel) and using it to set the italic text for those in the parentheses. The problem is the text in the parentheses is not set to italic. Not sure where my error is..

The code looks like this:

static inline NSRegularExpression * ParenthesisRegularExpression() {
    static NSRegularExpression *_parenthesisRegularExpression = nil;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _parenthesisRegularExpression = [[NSRegularExpression alloc] initWithPattern:@"\\([^\\(\\)]+\\)" options:NSRegularExpressionCaseInsensitive error:nil];
    });

    return _parenthesisRegularExpression;
}

-(TTTAttributedLabel*)setItalicTextForLabel:(TTTAttributedLabel*)attributedLabel fontSize:(float)Size stringToBeSet:(NSString*)string
{
    [attributedLabel setText:string afterInheritingLabelAttributesAndConfiguringWithBlock:^NSMutableAttributedString *(NSMutableAttributedString *mutableAttributedString)
    {
        NSRange stringRange = NSMakeRange(0, [mutableAttributedString length]);
        NSRegularExpression *regexp = ParenthesisRegularExpression();
        [regexp enumerateMatchesInString:[mutableAttributedString string] options:0 range:stringRange usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
            UIFont *italicSystemFont = [UIFont italicSystemFontOfSize:Size];
            CTFontRef italicFont = CTFontCreateWithName((__bridge CFStringRef)italicSystemFont.fontName, italicSystemFont.pointSize, NULL);
            if (italicFont) {
                [mutableAttributedString removeAttribute:(NSString *)kCTFontAttributeName range:result.range];
                [mutableAttributedString addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)italicFont range:result.range];
                CFRelease(italicFont);

                [mutableAttributedString removeAttribute:(NSString *)kCTForegroundColorAttributeName range:result.range];
                [mutableAttributedString addAttribute:(NSString*)kCTForegroundColorAttributeName value:(id)[[UIColor grayColor] CGColor] range:result.range];
            }
        }];

        return mutableAttributedString;
    }];
    return attributedLabel;
}

I am calling it this way:mylabel = [self setItalicTextForLabel:descriptionLabel fontSize:23 stringToBeSet:string];

Need some guidance on what I am doing wrong.

Upvotes: 1

Views: 1561

Answers (1)

Ivan Vučica
Ivan Vučica

Reputation: 9669

I have never used TTTAttributedLabel, and my experience with NSAttributedString comes from playing with NSTextView on OS X.

That said, why not refactor the code a bit to pass an NSAttributedString directly into setText:afterInheritingLabelAttributesAndConfiguringWithBlock:? That scenario seems to have been made possible two years ago.

In fact, why not use setText:?

Sets the text displayed by the label.

@param text An NSString or NSAttributedString object to be displayed by the label. If the specified text is an NSString, the label will display the text like a UILabel, inheriting the text styles of the label. If the specified text is an NSAttributedString, the label text styles will be overridden by the styles specified in the attributed string.

@discussion This method overrides UILabel -setText: to accept both NSString and NSAttributedString objects. This string is nil by default.

I've taken the liberty of renaming your method and cleaning up the code. Without testing, of course, considering that I don't have TTTAttributedLabel available, and am too lazy to set up a demo project just to answer this question :-)

-(void)applyItalicTextInParenthesisOfString:(NSString*)string
                                    toLabel:(TTTAttributedLabel*)attributedLabel
                                     fontSize:(float)size
{
    NSMutableAttributedString * mutableAttributedString = [[NSMutableAttributedString alloc] initWithString:string];
    NSRange stringRange = NSMakeRange(0, [mutableAttributedString length]);
    NSRegularExpression *regexp = ParenthesisRegularExpression();

    UIFont *italicSystemFont = [UIFont italicSystemFontOfSize:size];
    CTFontRef italicFont = CTFontCreateWithName((__bridge CFStringRef)italicSystemFont.fontName, italicSystemFont.pointSize, NULL);

    [regexp enumerateMatchesInString:[mutableAttributedString string] options:0 range:stringRange usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {

        if (italicFont)
        {
            // No need to remove an attribute; the string was already an
            // NSString, without any attributes.
            // [mutableAttributedString removeAttribute:(NSString *)kCTFontAttributeName range:result.range];
            // [mutableAttributedString removeAttribute:(NSString *)kCTForegroundColorAttributeName range:result.range];

            [mutableAttributedString addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)italicFont range:result.range];
            [mutableAttributedString addAttribute:(NSString*)kCTForegroundColorAttributeName value:(id)[[UIColor grayColor] CGColor] range:result.range];
        }
    }];

    CFRelease(italicFont);

    [attributedLabel setText:string]
}

I'm also somewhat old-fashioned, so for readability, I'd avoid ARC and blocks.

Upvotes: 3

Related Questions