NSAttributedString高度由width和numberOfLines限制
我需要计算不使用UILabel的sizeThatFits方法的自定义标签中的文本矩形。 下面的代码不能正常工作。 主要思想是在index = numberOfLines – 1处查找CTLine,并返回其最大y位置。 但是,结果文本高度有时太大,有时不足以画出最后一行。
- (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); }
在我的UILabel子类中使用的这个类的NSAttributedString
@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子类中实际上是错误的
解决scheme似乎是最简单的。 没有必要得到线的起源和印刷的界限。 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)); } }