引言
由于最近工作需要实现一个类似脉脉动态的界面,其中展开显示全文功能,需要动态计算Label的大小后决定隐藏或者显示,之前一直使
- (CGSize)sizeWithFont:(UIFont *)font
方法,而在iOS7中用方法- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(nullable NSDictionary<NSString *, id> *)attributes context:(nullable NSStringDrawingContext *)context
,但是在实际运用中发现还是有一点小误差的。
关键字:全文
、Label高度计算
、展开全文
1 函数介绍
1.1 描述
- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(NSDictionary<NSString *,id> *)attributes context:(NSStringDrawingContext *)context;
根据上下文设定和显示特性计算并返回一个rect大小
1.2 参数
参数 | 说明 |
---|---|
size | 存放字符串的Label的size大小 |
options | 字符串排版的选项(下文会说明) |
attributes | 文字属性设置,至少需要font属性 |
context | 渲染上下文 |
1.2.1 关于options
options | 说明 |
---|---|
NSStringDrawingTruncatesLastVisibleLine | 如果文本内容超出指定的矩形限制,文本将被截去并在最后一个字符后加上省略号。 |
NSStringDrawingUsesLineFragmentOrigin | 启用自动换行 |
NSStringDrawingUsesFontLeading | 计算行高时使用行间距 |
NSStringDrawingUsesDeviceMetrics | 计算布局时使用图元字形(而不是印刷字体) |
- 一般我们使用
NSStringDrawingUsesLineFragmentOrigin
和NSStringDrawingUsesFontLeading
即可。
2 使用
直接上代码
NSString *contentText = @"南美足联同意国民竞技队请求,沙佩科恩斯队将获南美杯冠军。南美足联同意国民竞技队请求,沙佩科恩斯队将获南美杯冠军。南美足联同意国民竞技队请求,沙佩科恩斯队将获南美杯冠军。";
UILabel *DisplayLabel = [[UILabel alloc] init];
DisplayLabel.numberOfLines = 0;
DisplayLabel.text = contentText;
DisplayLabel.textColor = [UIColor orangeColor];
DisplayLabel.font = [UIFont systemFontOfSize:17];
DisplayLabel.frame = CGRectMake(20, 70, 200, 200);
[DisplayLabel sizeToFit];
DisplayLabel.backgroundColor = [UIColor greenColor];
[self.view addSubview:DisplayLabel];
//至少设置一个font属性
UIFont *fnt = self.DisplayLabel.font;
NSDictionary *dict = @{NSFontAttributeName: fnt};
//在为达到高度的情况下只有label的宽度有约束作用,高度最多为1000
CGSize defineSize = CGSizeMake(DisplayLabel.bounds.size.width, 1000);
//rect内的size即为计算所得的label大小
CGRect rect = [contentText boundingRectWithSize:defineSize
options:NSStringDrawingUsesLineFragmentOrigin |
NSStringDrawingUsesFontLeading
attributes:dict
context:nil];
结果显示
- 结果上会有小数点后一位的误差,需要各位爷自己调整下,如果有好的建议欢迎指教~
3 附加
- 展开显示全文的功能有时候还能通过计算行数来实现,送上一个coreText下的计算行数及每行内容的方法
//数组内为每行的内容,数组的count为行数
- (NSArray *)getLinesArrayOfStringInLabel:(UILabel *)label{
NSString *text = [label text];
UIFont *font = [label font];
//目的为了取到label的宽度
CGRect rect = [label frame];
CTFontRef myFont = CTFontCreateWithName(( CFStringRef)([font fontName]), [font pointSize], NULL);
NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:text];
[attStr addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)myFont range:NSMakeRange(0, attStr.length)];
CFRelease(myFont);
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString(( CFAttributedStringRef)attStr);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0,0,rect.size.width,100000));
CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL);
NSArray *lines = ( NSArray *)CTFrameGetLines(frame);
NSMutableArray *linesArray = [[NSMutableArray alloc]init];
for (id line in lines) {
CTLineRef lineRef = (__bridge CTLineRef )line;
CFRange lineRange = CTLineGetStringRange(lineRef);
NSRange range = NSMakeRange(lineRange.location, lineRange.length);
NSString *lineString = [text substringWithRange:range];
CFAttributedStringSetAttribute((CFMutableAttributedStringRef)attStr, lineRange, kCTKernAttributeName, (CFTypeRef)([NSNumber numberWithFloat:0.0]));
CFAttributedStringSetAttribute((CFMutableAttributedStringRef)attStr, lineRange, kCTKernAttributeName, (CFTypeRef)([NSNumber numberWithInt:0.0]));
[linesArray addObject:lineString];
}
CFRelease(frameSetter);
CFRelease(frame);
CFRelease(path);
return (NSArray *)linesArray;
}
最后附上github的demo。
欢迎各位看官老爷指教~