Mark Manson Mark Manson - 1 month ago 13
iOS Question

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.

Answer

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...