iosobjective-ctttattributedlabel

Specify multiple/conditional link colors in TTTAttributedLabel


I've added a link detector to TTTAttributedLabel that identifies @mentions and #hashtags and creates a link at that position in my TTTAttributedLabel instance:

- (void)highlightMentionsInString:(NSString *)text withColor:(UIColor *)color isBold:(BOOL)bold isUnderlined:(BOOL)underlined
{
    NSRegularExpression *mentionExpression = [NSRegularExpression regularExpressionWithPattern:@"(?:^|\\s)(@\\w+)" options:NO error:nil];

    NSArray *matches = [mentionExpression matchesInString:text
                                                  options:0
                                                    range:NSMakeRange(0, [text length])];
    for (NSTextCheckingResult *match in matches) {
        NSRange matchRange = [match rangeAtIndex:1];
        NSString *mentionString = [text substringWithRange:matchRange];
        NSRange linkRange = [text rangeOfString:mentionString];
        NSString* user = [mentionString substringFromIndex:1];
        NSString* linkURLString = [NSString stringWithFormat:@"user:%@", user];
        [self.attributedLabel addLinkToURL:[NSURL URLWithString:linkURLString] withRange:linkRange];
    }
}

I've also discovered that I can do this to easily change the link colors and attributes:

NSArray *keys = [[NSArray alloc] initWithObjects:(id)kCTForegroundColorAttributeName,(id)kCTUnderlineStyleAttributeName
                             , nil];
NSArray *objects = [[NSArray alloc] initWithObjects:color,[NSNumber numberWithInt:kCTUnderlineStyleNone], nil];
NSDictionary *linkAttributes = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];

self.attributedLabel.linkAttributes = linkAttributes;

But this changes the colors for every link attribute - including web links, hashtags, and mentions. Is there a way to create different link colors using a regular expression or range? Say if I wanted @mentions to be gray, @hashtags to be red, and web links to be blue?


Solution

  • I was just working on a similar problem and came across your question. I didn't know precisely how to inject some sort of different expressions to match other sorts of things in my label, so your first bit of code cleared that up.

    For your question though — what I did was change the TTTAttributedLabel method to one that adds the NSTextCheckingResult. So, if I make a few changes to your for loop in that method and use [self.label addLinkWithTextCheckingResult: attributes: ] and set the attributes as you suggest, now that loop looks like this:

    for (NSTextCheckingResult *match in matches) {
        NSRange matchRange = [match rangeAtIndex:1];
        NSString *mentionString = [text substringWithRange:matchRange];
        NSString* user = [mentionString substringFromIndex:1];
        NSString* linkURLString = [NSString stringWithFormat:@"user:%@", user];
        NSArray *keys = [[NSArray alloc] initWithObjects:(id)kCTForegroundColorAttributeName, (id)kCTUnderlineStyleAttributeName, nil];
        NSArray *objects = [[NSArray alloc] initWithObjects:color,[NSNumber numberWithInt:kCTUnderlineStyleNone], nil];
        NSDictionary *linkAttributes = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
        [self.label addLinkWithTextCheckingResult:match attributes:linkAttributes];
    }
    

    In my case, this will show # and @ in a toasted orange.

    And then I have the - (void)attributedLabel:(TTTAttributedLabel *)label didSelectLinkWithTextCheckingResult:(NSTextCheckingResult *)result TTTAttributedLabelDelegate method in my TTTAttributedLabelDelegate. That gets called with a NSTextCheckingResult when one taps on the # or @ text.

    Is this what you were looking for?