Search code examples
iosobjective-ccocoa-touchnsattributedstring

Change attributes of multiple parts of a NSMutableAttributedString


I need to check an NSMutableString against values I've inserted when it originally was an NSString.

An example of it is:

NString* textToDraw = @"";
textToDraw = [textToDraw stringByAppendingString:[[NSString alloc] initWithFormat:@"       
Summary of currently worked on process\n\nTitle name:\nResults for Process\n    %@\n%@\n%@\n, resultOne, resultTwo, resultThree]];

resultOne, resultTwo, resultThree are just standard NSString values

I then initialise a NSMutableAttributedString for some added formatting.

NSMutableAttributedString *summaryBody  = [[NSMutableAttributedString alloc]  initWithString:textToDraw];

CTFontRef centuryGothicStandard;
CTFontRef centuryGothicTitle;

centuryGothicStandard = CTFontCreateWithName(CFSTR("Century Gothic"), 12.0, nil);
centuryGothicTitle = CTFontCreateWithName(CFSTR("Century Gothic-Bold"), 24.0, nil);

//Modify the summary, so that the title is larger, and bolded, the subtitles are bolded, and the text is century gothic font
[summaryBody addAttribute:(id)kCTFontAttributeName
                    value:(__bridge id)centuryGothicStandard
                    range:NSMakeRange(0, [summaryBody length])];

What I need to do is modify resultOne, resultTwo and resultThree to be red, I tried the answered solution in Change attributes of substrings in a NSAttributedString but I do not understand the concept.

Can I simply loop through the NSMutableAttributedString and find a specific character I insert say '|' for a beginning point and '?' for an end point? I've searched for getting a specific index, but nothing related to NSAttributedMutatableString pops up just NSRange, which I won't know specifically.

Here is some pseudo code to help explain what I think could be a possible solution:

textToDraw = [textToDraw stringByAppendingString:[[NSString alloc] initWithFormat:@" Summary of currently worked on process\n\nTitle name:\nResults for Process\n    |%@?\n|%@?\n|%@?\n, resultOne, resultTwo, resultThree]];
(for int i = 0; i < [NSAttributedMutatableString length]; i++)
{
    if(char at i == '|')
    {
        get an NSRange from this value to the char at i == '?'
        [NSAttributedMutatableStringS addAttribute:(id)kCTForegroundColorAttributeName
                    value:(id)[UIColor redColor].CGColor
                    range:NSMakeRange(0, NSRangeAbove])];
    }
}

I currently can get the values of resultOne and such and create NSAttributedStrings with the added attribute of changing the colour, the only problem is of course not knowing the index value, so that is another possibility.


Solution

  • Searching for start-end characters or character sequences is ok if you are certain they will never appear in resultX strings...

    One approach would be to build a string piece by piece and create an array of ranges on the fly. At the end you simply slap the attributes on them.

    NSMutableString *mTextToDraw = [[NSMutableString alloc] init];
    NSMutableArray *mRangesToMod = [[NSMutableArray alloc] init];
    NSValue *mRange = nil;
    
    [mTextToDraw appendFormat:@"Summary of currently worked on process\n\nTitle name:\nResults for Process\n    "];
    
    mRange = [NSValue valueWithRange:NSMakeRange(mTextToDraw.length,resultOne.length)];;
    [mRangesToMod addObject: mRange];
    [mString appendFormat:@"%@\n",resultOne];
    
    mRange = [NSValue valueWithRange:NSMakeRange(mTextToDraw.length,resultTwo.length)];;
    [mRangesToMod addObject: mRange];
    [mString appendFormat:@"%@\n",resultTwo];
    
    mRange = [NSValue valueWithRange:NSMakeRange(mTextToDraw.length,resultThree.length)];;
    [mRangesToMod addObject: mRange];
    [mString appendFormat:@"%@\n",resultThree];
    
    NSMutableAttributedString *summaryBody = [[NSMutableAttributedString alloc] initWithString:mTextToDraw];
    
    for (NSValue *vRange in mRangesToMod)
    {
        NSRange range = vRange.rangeValue;
    
        [summaryBody setAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"Roboto-Light" size:smallFont]}
                             range:range];
    
        // or you can use addAttribute...
    }
    

    I used "Roboto-Light" in my app - it won't work in yours as is. Just as an example. For test just put there some font other then the basic (original) one...