iPhone sdk: NSMutableAttributedString некорректное поведение при использовании CTFramesetterCreateFrame - PullRequest
2 голосов
/ 25 января 2012

Я пытаюсь нарисовать текст с какой-то его частью другим цветом

Сначала выдайте это при использовании следующего кода:

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);

А потом рисуем рамку:

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);

По какой-то причине он показывает и "f", и "i", окрашенные в красный цвет. Когда я изменяю текст на «f1», «f!» Или что-то еще, все работает нормально. Даже когда я использую «afi» и диапазон как (1,1), он окрашивает «f» и «i» так, как будто он обрабатывает его как один символ.

Вторая проблема при рисовании внутри рамки с шириной, которая меньше ширины текста:

NSMutableAttributedString *test2 = [[NSMutableAttributedString alloc] initWithString:@"aaaaaaaaaaaaaaaaaaaa"];

CTLineBreakMode lineBreakMode;
lineBreakMode = kCTLineBreakByTruncatingTail;

// Apply selected truncation
CTParagraphStyleSetting paragraphStyleSetting = {kCTParagraphStyleSpecifierLineBreakMode, sizeof(CTLineBreakMode), &lineBreakMode};
CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(&paragraphStyleSetting, 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);

Всего 20 символов, те, что в индексах с 7 по 16 кажутся окрашенными в красный цвет (как и должно быть), CoreText добавляет знак усечения, как я и просил, но проблема в том, что он тоже окрашен в красный цвет, и я хочу, чтобы он оставался черным (так как цвет остальных усеченных символов черный).

Я провел некоторое исследование, и кажется, что при увеличении размера кадра на некоторое (случайное / специфичное для шрифта?) Значение в команде:

CGPathAddRect(path, NULL, CGRectMake(0, 0, self.frame.size.width + 10.0f, self.frame.size.height));

Сохраняет метку усечения черным, но из-за дополнительного пространства иногда метка усечения обрезается

Ответы [ 2 ]

2 голосов
/ 16 июля 2012
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)];
0 голосов
/ 25 января 2012

Это звучит как проблема с лигатурами . Хороший шрифт имеет специальные символы для некоторых комбинаций символов, которые выглядят лучше, чем отдельные символы. Например, во многих шрифтах To не выглядит хорошо, если визуализируется индивидуально, так как между вертикальной чертой T и началом o есть много места. Таким образом, предоставляются лигатуры, которые имеют более привлекательный интервал. Иногда персонажи даже соединяются, ваш fi является хорошим примером: некоторые шрифты предоставляют лигатуру, которая делает вершину f двойной как точка для i.

Так что вы можете отключить лигатуры, но установив атрибут kCTLigatureAttributeName в 0.

...