#ios4 #sizewithfont #catextlayer
#ios4 #размер с помощью шрифта #catextlayer
Вопрос:
Все мои исследования на данный момент, по-видимому, указывают на то, что сделать это точно невозможно. Единственные два варианта, доступные мне с самого начала, были:
a) Использование менеджера компоновки для CATextLayer — недоступно на iOS начиная с версии 4.0
б) Используйте sizeWithFont:constrainedToSize:lineBreakMode: и отрегулируйте рамку CATextLayer в соответствии с возвращаемым здесь размером.
Вариант (b), являющийся самым простым подходом, должен сработать. В конце концов, это отлично работает с UILabels. Но когда я применял то же самое вычисление фрейма к CATextLayer, фрейм всегда оказывался немного больше, чем ожидалось или требовалось.
Как оказалось, межстрочный интервал в CATextLayers и UILabels (для одного и того же шрифта и размера) отличается. В результате sizeWithFont (вычисления межстрочного интервала которого совпадали бы с вычислениями UILabels) не возвращает ожидаемый размер для CATextLayers.
Это дополнительно подтверждается печатью того же текста с использованием UILabel по сравнению с CATextLayer и сравнением результатов. Текст в первой строке идеально перекрывается (это тот же шрифт), но межстрочный интервал в CATextLayer немного короче, чем в UILabel. (Извините, я не могу загрузить скриншот прямо сейчас, поскольку те, которые у меня уже есть, содержат конфиденциальные данные, и в настоящее время у меня нет времени создавать пример проекта для получения чистых скриншотов. Я загружу их позже для потомков, когда у меня будет время)
Это странная разница, но я подумал, что можно было бы отрегулировать интервал в CATextLayer, указав соответствующий атрибут для NSAttributedString, который я там использую, но, похоже, это не так. Изучаю атрибуты CFStringAttributes.h Я не могу найти ни одного атрибута, который мог бы быть связан с межстрочным интервалом.
Итог:
Похоже, что невозможно использовать CATextLayer на iOS в сценарии, где слой должен соответствовать своему тексту. Я прав в этом или я что-то упускаю?
P.S:
-
Причина, по которой я хотел использовать CATextLayer и NSAttributedString, заключается в том, что отображаемая строка должна быть по-разному окрашена в разных точках. Я думаю, мне просто нужно вернуться к рисованию строк вручную, как всегда …. конечно, всегда есть возможность взломать результаты из sizeWithFont, чтобы получить правильную высоту строки.
-
Немного злоупотребляем тегами «code», чтобы сделать сообщение более читаемым.
-
Я не могу пометить сообщение ‘CATextLayer’ — удивительно, но на данный момент таких тегов не существует. Если кто-то с достаточной репутацией наткнется на этот пост, пожалуйста, отметьте его соответствующим образом.
Комментарии:
1. Я только что столкнулся с этой проблемой … поспешите с ответом.
2. @All, в случае, если это неясно, вопрос относится строго к изменению размера 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), amp;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.
Комментарии:
1. Извините, прошло некоторое время, и в настоящее время у меня нет кода или времени для тестирования этого. Я обязательно проверю, когда смогу. Тем временем, если кто-то еще, столкнувшийся с этим ответом, сможет проверить, что он работает, я пометлю его как «отвеченный».
2. Через 6 месяцев я, наконец, снова столкнулся с этой проблемой. 🙂 И решение сработало. Большое спасибо, Мустафа!!
Ответ №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
Комментарии:
1. Ах, видишь. Как отмечалось в нижней части моего вопроса, мне специально приходится использовать CATextLayers из-за их необычных возможностей форматирования. В противном случае UILabel прекрасно справился бы с этой задачей. В любом случае, прошло так много времени с тех пор, как был опубликован этот вопрос, о единственной зацепке, которая пока что давала какие-то надежды, — это @Mustafa. Трагично, что я так долго не мог это сделать. Кто-нибудь собирается это сделать?
Ответ №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);
}
Комментарии:
1. Извините, но я не думаю, что это отвечает на вопрос. Вопрос заключается в изменении размера CATextLayer по вертикали, чтобы обернуть / подогнать любую строку, в то время как ответ заключается в выравнивании по вертикали — это тоже одна строка текста.