Подтвердить что ты не робот

Изменение размера 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" - удивительно, что на данный момент таких тегов нет. Если кто-то с достаточной репутацией сталкивается с этим сообщением, пожалуйста, отметьте его соответствующим образом.

4b9b3361

Ответ 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);
}