iOS开发中经常需要根据字符串的数量和字体大小来计算UILabel的高度。
系统为我们提供了两种方法:
1.NSString和NSAttributedString的boundingRectWithSize方法
2.UIView的sizeThatFits方法
这两种方法使用起来很简单,但是有不少坑要填。
先来看第一种方法
计算下面这个string的size,并且限制label最多展示两行
NSString *str = @"从她分享的照片和贴文中不难看出对警察工作的热爱从她分享的照片和贴文中不难看出对警察工作的热爱";
CGSize size = [str boundingRectWithMaxSize:maxSize font:bigFont maxLineNumber:2];
// NSString category
- (CGSize)boundingRectWithMaxSize:(CGSize)maxSize
font:(UIFont *)font
maxLineNumber:(NSUInteger)maxLineNumber{
if (font==nil || self==nil) {
return CGSizeZero;
}
CGRect rect = [self boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:font} context:nil];
if (maxLineNumber>0){
CGFloat maxHeight = maxLineNumber * font.lineHeight;
if (rect.size.height > maxHeight){
return CGSizeMake(rect.size.width, maxHeight);
}
}
return rect.size;
}
有时还要添加行间距
这就要用到NSMutableAttributedString
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
style.lineSpacing = 4; //行间距
NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] initWithString:str];
[attrStr addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, attrStr.length)];
[attrStr addAttribute:NSFontAttributeName value:bigFont range:NSMakeRange(0, attrStr.length)];
CGRect rect = [attrStr boundingRectWithMaxSize:maxSize font:bigFont maxLineNumber:2];
linespacing.png
这样行间距高度就计算出来了。
但是这并没结束。
当文字比较少,只有一行的时候,你会看到这样:
oneline-spacing.pngLabel文字下方多了一段空白高度。没错,这就是你刚才设置的行间距(纯英文字符不会有这个问题,只要字符串中包含中文就会这样,系统对中文的支持还是不到位)
这就需要我们在字符串只有一行的时候减去行间距:
CGRect rect = [self boundingRectWithSize:maxSize options:options context:nil];
if ((rect.size.height - font.lineHeight) <= lineSpacing && [self.string containsChinese]) {
rect = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height-lineSpacing);
}
这样就完美了吗?高兴的太早了。
当我设置文字的截断模式的时候又出问题了
style.lineBreakMode = NSLineBreakByTruncatingTail;
label.numberOfLines = 2;
label.attributedText = attStr;
虽然label行数设置为2,但是计算粗来的高度只有一行!
原来当你设置NSLineBreakByTruncatingTail的时候,NSAttributedString的boundingRectWithSize方法只会按照一行来计算高度。
NSLineBreakByClipping, NSLineBreakByTruncatingHead, NSLineBreakByTruncatingTail, NSLineBreakByTruncatingMiddle
这几种LineBreakMode都是这样
怎么办呢?
很简单,不要为NSAttributedString设置LineBreakMode,在UILabel上设置这个属性:
label.lineBreakMode = NSLineBreakByTruncatingTail;
现在算是完美了吧?
不知道。目前已经满足我们的需求了。以后遇到坑再填吧。
第二种方法跟第一种差不多,也有上面类似的问题,按上面的解决方法也可以自己封装一个工具,这里就不赘述了。
网友评论