2017-02-11 29 views
0

Мне нужно вычислить текст rect на моей пользовательской метке, не используя метод sizeThatFits от UILabel. Код ниже работает неправильно. Основная идея - найти CTLine в index = numberOfLines - 1 и вернуть ее максимальную позицию y. Но в результате высота текста иногда слишком велика и иногда недостаточно, чтобы нарисовать последнюю строку.NSAttributedString высота ограничена по ширине и числуOfLines

- (CGSize)fittingSizeWithSize:(CGSize)size numberOfLines:(NSInteger)numberOfLines { 
    if (numberOfLines == 0) { 
     return [self fittingSizeWithSize:size]; 
    } 

    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)self); 

    if (framesetter == NULL) { 
     return CGSizeZero; 
    } 

    CGPathRef path = CGPathCreateWithRect(CGRectMake(0,0,size.width,size.height), NULL); 
    CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, self.length), path, NULL); 

    NSArray *lines = (NSArray *) CTFrameGetLines(frame); 
    if (lines.count == 0) { 
     return CGSizeZero; 
    } 
    NSUInteger lineIndex = MIN((NSUInteger)numberOfLines, lines.count) - 1; 
    CTLineRef line = (__bridge CTLineRef) lines[lineIndex]; 

    CGPoint origins[[lines count]]; 
    CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins); 

    CGAffineTransform transform = CGAffineTransformMakeTranslation(0, size.height); 
    transform = CGAffineTransformScale(transform, 1, -1); 
    CGRect lineRect; 
    CGFloat ascent; 
    CGFloat descent; 
    lineRect.size.width = (CGFloat)CTLineGetTypographicBounds(line, &ascent, &descent, NULL); //8 
    lineRect.size.height = ascent + descent; 
    lineRect.origin.y = CGPointApplyAffineTransform(origins[lineIndex], transform).y; 
    CGFloat height = CGRectGetMaxY(lineRect); 

    CFRelease(path); 
    CFRelease(framesetter); 

    return CGSizeMake(size.width, height); 
} 

Эта категория NSAttributedString используется в моем UILabel подкласса

@implementation SMBDLabel 

- (void)drawTextInRect:(CGRect)rect { 
    if (self.attributedText) { 
     CGContextRef ctx = UIGraphicsGetCurrentContext(); 
     [self.attributedText drawInContext:ctx viewBounds:rect]; 
    } else { 
     [super drawTextInRect:rect]; 
    } 
} 

- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines { 
    CGSize size = [self.attributedText fittingSizeWithSize:bounds.size numberOfLines:numberOfLines]; 
    return CGRectMake(0, 0, size.width, size.height); 
} 

- (CGSize)sizeThatFits:(CGSize)size { 
    return [self.attributedText fittingSizeWithSize:size numberOfLines:self.numberOfLines]; 
} 

@end 

Я понятия не имею, где моя ошибка. Возможно, ошибка на самом деле в подклассе UILabel

+1

Зачем использовать основной текст, когда NSAttributedString уже имеет 'boundingRectWithSize: опции: контекст:'? – matt

+0

Как и я не могу использовать NSTextAttachment (есть ошибка с переносом строк и без использования обходного пути) Я рисую свои пользовательские вложения изображений. Есть проблема с заменой UILabel на подклассы UIView. – Arsynth

+0

Я не следую никому из этого. Теперь у вас есть текстовый набор. Вам не нужен Core Text для чего-либо. И UITextView позволяет напрямую использовать Text Kit, а также имитировать поведение UILabel. – matt

ответ

0

Решение кажется простейшим. Нет необходимости получать происхождение строк и привязку к шрифтам. CTFramesetterSuggestFrameSizeWithConstraints с диапазоном текста конкретного текста будет делать всю работу

- (CGSize)fittingSizeWithSize:(CGSize)size numberOfLines:(NSInteger)numberOfLines { 
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)self); 

    if (!framesetter) { 
     return CGSizeZero; 
    } 

    if (numberOfLines == 0) { 
     CGSize textSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0,0), NULL, size, NULL); 

     if (framesetter != NULL) { 
      CFRelease(framesetter); 
     } 

     return CGSizeMake(ceilf(textSize.width), ceilf(textSize.height)); 
    } else { 
     CGPathRef path = CGPathCreateWithRect(CGRectMake(0, 0, size.width, CGFLOAT_MAX), NULL); 
     CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, self.length), path, NULL); 
     if (path != NULL) { 
      CFRelease(path); 
     } 


     NSArray *lines = (NSArray *)CTFrameGetLines(frame); 
     __block CFIndex len = 0; 

     [lines enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 
      if (numberOfLines > 0 && idx == numberOfLines) { 
       *stop = YES; 
       return; 
      } 

      CTLineRef line = (__bridge CTLineRef)obj; 
      CFRange range = CTLineGetStringRange(line); 

      len += range.length; 
     }]; 

     CFRange strRange = CFRangeMake(0, len); 
     CGSize textSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, strRange, NULL, size, NULL); 

     if (framesetter != NULL) { 
      CFRelease(framesetter); 
     } 

     return CGSizeMake(ceilf(textSize.width), ceilf(textSize.height)); 
    } 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^