Изменение размера CATextLayer для размещения текста в iOS
Все мои исследования пока показывают, что это невозможно сделать точно. Единственные два варианта, доступные мне вначале:
a) Использование менеджера макетов для CATextLayer - недоступно в iOS с 4.0
b) Используйте sizeWithFont: constrainedToSize: lineBreakMode: и отрегулируйте кадр CATextLayer в соответствии с размером, указанным здесь.
Вариант (b), являющийся простейшим подходом, должен работать. В конце концов, он отлично работает с UILabels. Но когда я применил тот же расчет кадра к CATextLayer, кадр всегда оказывался немного больше, чем ожидалось или требовалось.
Как оказалось, интервал между строками в CATextLayers и UILabels (для одного и того же шрифта и размера) отличается. В результате sizeWithFont (расчеты межстрочного интервала которого совпадают с вычислениями UILabels) не возвращает ожидаемый размер для CATextLayers.
Это еще раз подтверждается печатью того же текста с использованием UILabel, в отличие от CATextLayer и сравнения результатов. Текст в первой строке полностью перекрывается (это тот же шрифт), но интервал между строками в CATextLayer немного короче, чем в UILabel. (Извините, я не могу загрузить скриншот прямо сейчас, поскольку те, которые у меня уже есть, содержат конфиденциальные данные, и сейчас у меня нет времени, чтобы сделать образец проекта для очистки скриншотов. Я загружу их позже для потомков, когда У меня есть время)
Это странная разница, но я подумал, что можно будет отрегулировать интервал в CATextLayer, указав соответствующий атрибут для NSAttributedString, который я там использую, но это, похоже, не так. Заглядывая в CFStringAttributes.h Я не могу найти ни одного атрибута, который может быть связан с интервалом между строками.
Bottomline:
Таким образом, кажется, что нельзя использовать CATextLayer для iOS в сценарии, где слой должен соответствовать его тексту. Я прав, или я чего-то не хватает?
P.S:
-
Причина, по которой я хотел использовать CATextLayer и NSAttributedString, состоит в том, что отображаемая строка должна быть по-разному окрашена в разные точки. Наверное, мне просто нужно вернуться к рисованию строк вручную, как всегда... Конечно, всегда есть возможность взломать результаты от sizeWithFont, чтобы получить правильную высоту строки.
-
Неправильное использование тегов "code", чтобы сделать сообщение более читаемым.
-
Я не могу отметить сообщение "CATextLayer" - удивительно, что на данный момент таких тегов нет. Если кто-то с достаточной репутацией сталкивается с этим сообщением, пожалуйста, отметьте его соответствующим образом.
Ответы
Ответ 1
Попробуйте следующее:
- (CGFloat)boundingHeightForWidth:(CGFloat)inWidth withAttributedString:(NSAttributedString *)attributedString {
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString( (CFMutableAttributedStringRef) attributedString);
CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(inWidth, CGFLOAT_MAX), NULL);
CFRelease(framesetter);
return suggestedSize.height;
}
Вам нужно будет преобразовать NSString в NSAttributedString. В случае CATextLayer
вы можете использовать следующий подкласс CATextLayer
:
- (NSAttributedString *)attributedString {
// If string is an attributed string
if ([self.string isKindOfClass:[NSAttributedString class]]) {
return self.string;
}
// Collect required parameters, and construct an attributed string
NSString *string = self.string;
CGColorRef color = self.foregroundColor;
CTFontRef theFont = self.font;
CTTextAlignment alignment;
if ([self.alignmentMode isEqualToString:kCAAlignmentLeft]) {
alignment = kCTLeftTextAlignment;
} else if ([self.alignmentMode isEqualToString:kCAAlignmentRight]) {
alignment = kCTRightTextAlignment;
} else if ([self.alignmentMode isEqualToString:kCAAlignmentCenter]) {
alignment = kCTCenterTextAlignment;
} else if ([self.alignmentMode isEqualToString:kCAAlignmentJustified]) {
alignment = kCTJustifiedTextAlignment;
} else if ([self.alignmentMode isEqualToString:kCAAlignmentNatural]) {
alignment = kCTNaturalTextAlignment;
}
// Process the information to get an attributed string
CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0);
if (string != nil)
CFAttributedStringReplaceString (attrString, CFRangeMake(0, 0), (CFStringRef)string);
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, CFAttributedStringGetLength(attrString)), kCTForegroundColorAttributeName, color);
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, CFAttributedStringGetLength(attrString)), kCTFontAttributeName, theFont);
CTParagraphStyleSetting settings[] = {kCTParagraphStyleSpecifierAlignment, sizeof(alignment), &alignment};
CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(settings, sizeof(settings) / sizeof(settings[0]));
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, CFAttributedStringGetLength(attrString)), kCTParagraphStyleAttributeName, paragraphStyle);
CFRelease(paragraphStyle);
NSMutableAttributedString *ret = (NSMutableAttributedString *)attrString;
return [ret autorelease];
}
НТН.
Ответ 2
У меня есть намного более легкое решение, которое может или не может работать для вас.
Если вы не делаете ничего особенного с CATextLayer, что вы не можете использовать UILabel, вместо этого создайте CALayer и добавьте слой UILabel в CALayer
UILabel*label = [[UILabel alloc]init];
//Do Stuff to label
CALayer *layer = [CALayer layer];
//Set Size/Position
[layer addSublayer:label.layer];
//Do more stuff to layer
Ответ 3
С LabelKit вам больше не нужен CATextLayer
. Больше нет неправильного межстрочного интервала и более широких символов, все отрисовывается так же, как UILabel, но при этом анимируется.
Ответ 4
Эта страница дала мне достаточно, чтобы создать простой центрированный горизонтальный CATextLayer: http://lists.apple.com/archives/quartz-dev/2008/Aug/msg00016.html
- (void)drawInContext:(CGContextRef)ctx {
CGFloat height, fontSize;
height = self.bounds.size.height;
fontSize = self.fontSize;
CGContextSaveGState(ctx);
CGContextTranslateCTM(ctx, 0.0, (fontSize-height)/2.0 * -1.0);
[super drawInContext:ctx];
CGContextRestoreGState(ctx);
}