Изменение размера CATextLayer, чтобы соответствовать тексту на iOS
все мои исследования до сих пор, кажется, указывают на то, что это невозможно сделать точно. С самого начала мне были доступны только два варианта:--1-->
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 я не могу найти ни одного атрибута, который мог бы быть связан с межстрочным интервалом.
итог:
поэтому кажется, что невозможно использовать CATextLayer на iOS в сценарии, где слой должен соответствовать тексту. Я прав или что-то упускаю?
П. С.:
причина, по которой я хотел использовать CATextLayer и NSAttributedString, заключается в том, что строка, которая будет отображаться, должна быть окрашена по-разному в разных точках. Я думаю, мне просто придется вернуться к рисованию струн вручную, как всегда....конечно, всегда есть возможность взлома результатов от sizeWithFont, чтобы получить правильный высота строк.
злоупотребление тегами " код " немного, чтобы сделать сообщение более читаемым.
Я не могу пометить сообщение "CATextLayer" - удивительно, что на данный момент таких тегов нет. Если кто-то с достаточной репутацией натыкается на этот пост, пожалуйста, отметьте его соответствующим образом.
3 ответов
попробуйте это:
- (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];
}
HTH.
У меня есть гораздо проще решение, которое может или не может работать для вас.
Если вы не делаете ничего особенного с 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
эта страница дала мне достаточно, чтобы создать простой по центру горизонтально 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);
}