iOS开发的过程中,总是避免不了各种高度的自适应,如:UILabel、UITextView、UITableViewCell的高度自适应...而这些适应大部分都源自文本的适应。
计算文本高度的方法有很多种,而我们平时的使用中,富文本的使用几率要大于普通文本,下面以富文本为例介绍两种获取文本高度的方式:
第一种:通过UILabel获取文本的高度
NSString *str = @"朱雀桥边野草花,乌衣巷口夕阳斜。旧时王谢堂前燕,飞入寻常百姓家。";
NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:str];
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
style.lineSpacing = 10;
UIFont *font = [UIFont systemFontOfSize:14];
[attributeString addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, str.length)];
[attributeString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, str.length)];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 1)];
label.font = [UIFont systemFontOfSize:14];
label.numberOfLines = 0;
label.attributedText = attributeString;
CGSize size = [label sizeThatFits:CGSizeMake(label.frame.size.width, CGFLOAT_MAX)];
NSLog(@"size:%@", NSStringFromCGSize(size));
NSLog(@"label.frame.size:%@", NSStringFromCGSize(label.frame.size));
可以看到打印结果为:
size:{196, 70.5}
label.frame.size:{200, 1}
在label调用完sizeThatFits:
之后,会返回根据条件适应好的size(本身的size并不发生改变),可以通过size.height拿到文本适应后的高度。
但是这种方法有些时候取到的高度会有问题,比如要显示的文本为:@"朱雀桥边野草花"时,上面的代码打印的结果为:
size:{98, 27} //单行高度包含了行间距
label.frame.size:{200, 1}
由于上面的代码显示的文本是富文本,文本的高度包含文字高度的同时,还包含有行间距,但是当UILabel显示的内容为1行时,label调用完sizeThatFits:
之后返回的size高度是包含行间距的。
当UILabel显示的文本行数大于等于2行时,sizeThatFits:后拿到的高度是准确的,当UILabel显示的文本行数是1行时,拿到的高度需要减去行间距后才是正确的适应高度
第二种:调用字符串的
boundingRectWithSize
获取文本的高度
NSString *str = @"朱雀桥边野草花,乌衣巷口夕阳斜。旧时王谢堂前燕,飞入寻常百姓家。";
NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:str];
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
style.lineSpacing = 10;
UIFont *font = [UIFont systemFontOfSize:14];
[attributeString addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, str.length)];
[attributeString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, str.length)];
NSStringDrawingOptions options = NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading;
CGRect rect = [attributeString boundingRectWithSize:CGSizeMake(200, CGFLOAT_MAX) options:options context:nil];
NSLog(@"size:%@", NSStringFromCGSize(rect.size));
可以看到打印结果为:
size:{196, 70.12109375}
要显示的文本为:@"朱雀桥边野草花"时,上面的代码打印的结果为:
size:{98, 26.70703125} //单行文本的行高同样包含行间距
以上两种方式都能获取到文本的高度,同样在显示富文本时,如果文本的行数是1行,获取到的文本高度都有问题,我们期望得到的是文本的高度(不包含行间距),这时候就需要判断了。
//文本的高度减去字体高度小于等于行间距,判断为当前只有1行
if ((rect.size.height - font.lineHeight) <= style.lineSpacing) {
rect = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height-style.lineSpacing);
}
到这里当文本只有1行时,获取准确的高度的问题好像得到了解决。当现实的文本是@"朱雀桥边野草花"时,打印的结果为:
size:{98, 26.70703125} //加判断条件之前
size:{98, 16.70703125} //加判断条件之后
获取的高度确实为字体的高度,不包含行间距了,然而在测试的时候悲催的发现,当显示文本是@"sfklsdkfjsdlfjsdjfd"时,纯英文的一段测试数据,上面代码的打印结果为:
size:{113.4013671875, 6.70703125}
唉,我去,高度怎么变成这么点儿了?在反复测试之后发现,只要文本中包含有中文时,计算单行文本高度就包含行间距,在文本是纯英文时,单行文本的高度不包含行间距(注:2行或2行以上的纯英文计算的高度是没问题的),so...判断条件又变成了下边这样:
if ((rect.size.height - _font.lineHeight) <= paragraphStyle.lineSpacing) {
if ([self containChinese:str]) { //如果包含中文
rect = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height-paragraphStyle.lineSpacing);
}
}
//判断如果包含中文
- (BOOL)containChinese:(NSString *)str {
for(int i=0; i< [str length];i++){
int a = [str characterAtIndex:i];
if( a > 0x4e00 && a < 0x9fff){
return YES;
}
}
return NO;
}
到这里问题就算是解决了,由于笔者能力有限,只会利用现掌握的知识解决这种问题,如果有大神有好的办法,还望不吝赐教,分享一下!