Изменение размера 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 в сценарии, где слой должен соответствовать тексту. Я прав или что-то упускаю?

П. С.:

  1. причина, по которой я хотел использовать CATextLayer и NSAttributedString, заключается в том, что строка, которая будет отображаться, должна быть окрашена по-разному в разных точках. Я думаю, мне просто придется вернуться к рисованию струн вручную, как всегда....конечно, всегда есть возможность взлома результатов от sizeWithFont, чтобы получить правильный высота строк.

  2. злоупотребление тегами " код " немного, чтобы сделать сообщение более читаемым.

  3. Я не могу пометить сообщение "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);
}