Reputation: 519
I'm trying to draw text with some part of it in different color
First issue it that when using the following code:
NSMutableAttributedString *test1 = [[NSMutableAttributedString alloc] initWithString:@"fi"];
// Should color only the first character "f"
[test1 addAttribute:(id)kCTForegroundColorAttributeName value:(id)[[UIColor redColor] CGColor] range:NSMakeRange(0, 1)];
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)test1);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height));
CTFrameRef textFrame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, test1.string.length), path, NULL);
And then drawing the frame:
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
// Flip the coordinate system
CGContextScaleCTM(context, 1.0, -1.0);
CTFrameDraw(textFrame, context);
CGContextRestoreGState(context);
For some reason it shows both "f" and "i" colored in red. When I change the text to "f1" , "f!", or anything else it works OK. Even when I use "afi" and range as (1,1) it colors both "f" and "i" as if it treats it as a single character.
Second issue, when drawing inside a frame with width which is less that the width of the text:
NSMutableAttributedString *test2 = [[NSMutableAttributedString alloc] initWithString:@"aaaaaaaaaaaaaaaaaaaa"];
CTLineBreakMode lineBreakMode;
lineBreakMode = kCTLineBreakByTruncatingTail;
// Apply selected truncation
CTParagraphStyleSetting paragraphStyleSetting = {kCTParagraphStyleSpecifierLineBreakMode, sizeof(CTLineBreakMode), &lineBreakMode};
CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(¶graphStyleSetting, 1);
[test1 addAttribute:(NSString *)kCTParagraphStyleAttributeName value:(__bridge id)paragraphStyle range:NSMakeRange(0, test2.string.length)];
[test1 addAttribute:(id)kCTForegroundColorAttributeName value:(id)[[UIColor redColor] CGColor] range:NSMakeRange(7, 16)];
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)test2);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height));
CTFrameRef textFrame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, test1.string.length), path, NULL);
There are total 20 characters, the ones at indexes 7 to 16 appear colored in red (as they should), CoreText adds a truncation mark as I requested but the problem is that it colored in red too and I want it to remain black (as the remaining truncated characters color is black).
I did some study and it seems that when increasing the frame size by some (random/font specific?) value in the command:
CGPathAddRect(path, NULL, CGRectMake(0, 0, self.frame.size.width + 10.0f, self.frame.size.height));
It keeps the truncation mark black, but because of the extra space sometimes the truncation mark is clipped
Upvotes: 2
Views: 1498
Reputation: 21
NSMutableAttributedString * string = [[NSMutableAttributedString alloc] initWithString:@"firstsecondthird"];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0,5)];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor greenColor] range:NSMakeRange(5,6)];
[string addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(11,5)];
Upvotes: 2
Reputation: 92335
This sounds like an issue with ligatures. A good font has special characters for some combinations of characters that look better than the individual characters. For example, in a lot of fonts To
doesn't look good if rendered individually since there's a lot of space between the vertical bar of T
and the start of the o
. So ligatures are provided that have a more appealing spacing. Sometimes the characters even get connect, your fi
is a good example: some fonts provide a ligature that makes the top of the f
double as the dot for the i
.
So you may want to turn the ligatures off but setting the attribute kCTLigatureAttributeName to 0.
Upvotes: 0