一、前言
前段時間來了一個新設計,將App的風格修改了一遍。在顯示文字時,增加了行間距。原本以為只是展示和計算高度的時候添加上富文本的lineSpace屬性即可,但是結果在顯示一行中文的時候,卻怎么也計算字體的時候多了一個行間距的高度,展示的Label也多了一個行間距的高度。經過查找資料,網上也有人遇到同樣的坑。計算高度時,需要將判斷一下是否中文與一行,如果是一行帶中文并且有行間距,此時總體高度應該減去行間距。展示的Label如果用的是自適應高度,也應該做一下判斷,一行中文帶行間距時,不設置Label的lineSpace屬性。如果你也遇到這樣坑,可以通過本文章的Demo解決,并封裝好一些方法,便于以后的使用。
二、文本獲取高度的方式:
通常計算文本的高度使用以下兩種方式,通過計算出來的高度計算父控件的總高度。
通過UILabel sizeThatFits獲取文本的高度
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 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));
boundingWithRect
NSString *text = @"恰同學少年,風華正茂";
NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:text];
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init]; style.lineSpacing = 10;
[attributeString addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, text.length)];
[attributeString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:14] range:NSMakeRange(0, text.length)]; NSStringDrawingOptions options = NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading;
CGRect rect = [attributeString boundingRectWithSize:CGSizeMake(100, MAXFLOAT) options:options context:nil];
三、中文富文本有行間距的坑:
計算文字高度的坑:
以上兩種計算方式在計算帶有中文,并且有行間距的富文本時,會出現在計算一行時,文本高度不對,多了一個行間距的高度。但在計算純英文時卻不會存在這個情況。這樣會導致在存在父控件時,父控件整體高度計算不對。
Paste_Image.png
給Label設置文本的坑:
在給Label設置富文本時,如果是一行并且帶中文,并且設置了間距lineSpace,結果多發現顯示出來多了一個間距的高度。
Paste_Image.png
四、解決方案:
計算文字高度的坑:
判斷行數與是否存在中文,當行數為一行,并且存在中文時,需要將計算結果的高度減去行間距。此時才為正確文本正確高度。
給Label設置文本的坑:
需要判斷是否超過一行,超過一行不設置富文本的lineSpace。
//文本的高度減去字體高度小于等于行間距,判斷為當前只有1行
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;
}
Paste_Image.png
五、封裝與使用(便于以后的使用)
對NSString進行以下方法的增加。
/**
- 計算文字高度,可以處理計算帶行間距的
*/
- (CGSize)boundingRectWithSize:(CGSize)size font:(UIFont*)font lineSpacing:(CGFloat)lineSpacing
{
NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithString:self];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineSpacing = lineSpacing;
[attributeString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, self.length)];
[attributeString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, self.length)];
NSStringDrawingOptions options = NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading;
CGRect rect = [attributeString boundingRectWithSize:size options:options context:nil];
// NSLog(@"size:%@", NSStringFromCGSize(rect.size));
//文本的高度減去字體高度小于等于行間距,判斷為當前只有1行
if ((rect.size.height - font.lineHeight) <= paragraphStyle.lineSpacing) {
if ([self containChinese:self]) { //如果包含中文
rect = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height-paragraphStyle.lineSpacing);
}
}
return rect.size;
}
//判斷如果包含中文
- (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;
}
/*
- 計算最大行數文字高度,可以處理計算帶行間距的
*/
-
(CGFloat)boundingRectWithSize:(CGSize)size font:(UIFont*)font lineSpacing:(CGFloat)lineSpacing maxLines:(NSInteger)maxLines{
if (maxLines <= 0) {
return 0;
}CGFloat maxHeight = font.lineHeight * maxLines + lineSpacing * (maxLines - 1);
CGSize orginalSize = [self boundingRectWithSize:size font:font lineSpacing:lineSpacing];
if ( orginalSize.height >= maxHeight ) {
return maxHeight;
}else{
return orginalSize.height;
}
}
/**
- 計算是否超過一行 用于給Label 賦值attribute text的時候 超過一行設置lineSpace
*/
-
(BOOL)isMoreThanOneLineWithSize:(CGSize)size font:(UIFont *)font lineSpaceing:(CGFloat)lineSpacing{
if ( [self boundingRectWithSize:size font:font lineSpacing:lineSpacing].height > font.lineHeight ) {
return YES;
}else{
return NO;
}
}