iOS中文行間距富文本高度與顯示那些坑

一、前言
前段時(shí)間來了一個(gè)新設(shè)計(jì),將App的風(fēng)格修改了一遍。在顯示文字時(shí),增加了行間距。原本以為只是展示和計(jì)算高度的時(shí)候添加上富文本的lineSpace屬性即可,但是結(jié)果在顯示一行中文的時(shí)候,卻怎么也計(jì)算字體的時(shí)候多了一個(gè)行間距的高度,展示的Label也多了一個(gè)行間距的高度。經(jīng)過查找資料,網(wǎng)上也有人遇到同樣的坑。計(jì)算高度時(shí),需要將判斷一下是否中文與一行,如果是一行帶中文并且有行間距,此時(shí)總體高度應(yīng)該減去行間距。展示的Label如果用的是自適應(yīng)高度,也應(yīng)該做一下判斷,一行中文帶行間距時(shí),不設(shè)置Label的lineSpace屬性。如果你也遇到這樣坑,可以通過本文章的Demo解決,并封裝好一些方法,便于以后的使用。

二、文本獲取高度的方式:
通常計(jì)算文本的高度使用以下兩種方式,通過計(jì)算出來的高度計(jì)算父控件的總高度。

通過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 = @"恰同學(xué)少年,風(fēng)華正茂";
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];
三、中文富文本有行間距的坑:
計(jì)算文字高度的坑:
以上兩種計(jì)算方式在計(jì)算帶有中文,并且有行間距的富文本時(shí),會(huì)出現(xiàn)在計(jì)算一行時(shí),文本高度不對,多了一個(gè)行間距的高度。但在計(jì)算純英文時(shí)卻不會(huì)存在這個(gè)情況。這樣會(huì)導(dǎo)致在存在父控件時(shí),父控件整體高度計(jì)算不對。

Paste_Image.png
給Label設(shè)置文本的坑:
在給Label設(shè)置富文本時(shí),如果是一行并且?guī)е形模⑶以O(shè)置了間距l(xiāng)ineSpace,結(jié)果多發(fā)現(xiàn)顯示出來多了一個(gè)間距的高度。

Paste_Image.png
四、解決方案:
計(jì)算文字高度的坑:
判斷行數(shù)與是否存在中文,當(dāng)行數(shù)為一行,并且存在中文時(shí),需要將計(jì)算結(jié)果的高度減去行間距。此時(shí)才為正確文本正確高度。
給Label設(shè)置文本的坑:
需要判斷是否超過一行,超過一行不設(shè)置富文本的lineSpace。
//文本的高度減去字體高度小于等于行間距,判斷為當(dāng)前只有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進(jìn)行以下方法的增加。

/**

  • 計(jì)算文字高度,可以處理計(jì)算帶行間距的
    */
  • (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));

//文本的高度減去字體高度小于等于行間距,判斷為當(dāng)前只有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;
    }
    /
    *
  • 計(jì)算最大行數(shù)文字高度,可以處理計(jì)算帶行間距的
    */
  • (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;
    }
    }
    /**

  • 計(jì)算是否超過一行 用于給Label 賦值attribute text的時(shí)候 超過一行設(shè)置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;
    }
    }

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容