iOS UILabel 设置内容的间距及高度的计算示例
前言
UILabel 是的使用频率是非常频繁,当文字较多的时候,会显得密密麻麻的,不利于UI显示及用户观看。通常我们需要对 Label 中“行间距”或“文字间距”进行调整,从而使文字没那么紧密,提高用户体验。
当调整“行间距”或“字间距”后,很多时候需要对Label进行高度自适应,此时会出现高度计算错误的问题,所以我们需要对“富文字”高度进行计算。计算结束后,经测试发现:当文字为1行并且全部文字为“中文”时,高度计算不准确,最后对该问题进行处理。
综上所述:分为以下三步进行设置“UILabel 内容的间距及高度的计算”
1. 通过使用 UILbael 的分类实现修改间距的功能。
2 .使用两种方法来计算:“富文字”的高度。
3. 对“高度计算结果”特殊情况进行处理。
一.设置 Label “行间距”或“字间距”
设置思路
普通的 NSString 文字,不能调整字体“行间距”或“字间距”,但
NSAttributedString 富文字,可以调整该间距,所以我们把普通的字体变为富文字,然后使用富文字对应方法即可设置间距。
设置过程
给 label 添加一个分类,在分类中声明并实现三种方法
@interface UILabel (ChangeLineSpaceAndWordSpace) //1.设置:行间距 + (void)changeLineSpaceForLabel:(UILabel *)label WithSpace:(float)space; //2.设置:字间距 + (void)changeWordSpaceForLabel:(UILabel *)label WithSpace:(float)space; //3.设置:行间距 与 字间距 + (void)changeSpaceForLabel:(UILabel *)label withLineSpace:(float)lineSpace WordSpace:(float)wordSpace; @end
1.设置:行间距
//传入需要设置的 Label 与需要设置的行间距数值 + (void)changeLineSpaceForLabel:(UILabel *)label WithSpace:(float)space { NSString *labelText = label.text; NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:labelText]; NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; [paragraphStyle setLineSpacing:space]; [attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [labelText length])]; label.attributedText = attributedString; [label sizeToFit]; }
2.设置:字间距
//传入需要设置的 Label 与需要设置的字间距数值 + (void)changeWordSpaceForLabel:(UILabel *)label WithSpace:(float)space { NSString *labelText = label.text; NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:labelText attributes:@{NSKernAttributeName:@(space)}]; NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; [attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [labelText length])]; label.attributedText = attributedString; [label sizeToFit]; }
3.同时设置: 行间距 与 字间距
//传入需要设置的 Label 与需要设置的行间距数值与字间距数值 + (void)changeSpaceForLabel:(UILabel *)label withLineSpace:(float)lineSpace WordSpace:(float)wordSpace { NSString *labelText = label.text; NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:labelText attributes:@{NSKernAttributeName:@(wordSpace)}]; NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; [paragraphStyle setLineSpacing:lineSpace]; [attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [labelText length])]; label.attributedText = attributedString; [label sizeToFit]; }
使用示例
//设置label内容,将lable内容变为有间距的内容 testLabel.text = @"测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字测试文字"; [UILabel changeLineSpaceForLabel:testLabel WithSpace:20];//设置testLabel中内容的行间距为20 [UILabel changeWordSpaceForLabel:self.testLabel WithSpace:20];//设置testLabel中内容的字间距为20 // [UILabel changeLineSpaceForLabel:self.testLabel WithSpace:20];//设置testLabel中内容的行间距为20,字间距为20
计算Label富文字高度
计算思路
可以直接计算富字体排布高度,该高度即为 Label 高度,也可以使用 UILable 的方法来计算 Label 高度
方法1.使用UILabel方法:sizeThatFits
- (CGRect)sizeThatFits:(CGSize)size;
通过UILabel的方法sizeThatFits,该方法需要传入一个参数,即可算出目前label高度。
参数1. size:其中size的宽度为label的宽度,size的一般填入最大高度。
CGSize size = [label sizeThatFits:CGSizeMake(label.frame.size.width, CGFLOAT_MAX)];
方法2.使用NSString方法:boundingWithRect
- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options context:(nullable NSStringDrawingContext *)context;
该方法需要传入3个参数:
参数1. size:其中size的宽度为label的宽度,size的一般填入最大高度。
参数2. options: 文本绘制时的附加选项
1. NSStringDrawingUsesLineFragmentOrigin (整个文本将以每行组成的矩形为单位计算整个文本的尺寸 )
2. NSStringDrawingUsesFontLeading (使用字体的行间距来计算文本占用的范围,即每一行的底部到下一行的底部的距离计算 )
3. NSStringDrawingUsesDeviceMetrics (将文字以图像符号计算文本占用范围,而不是以字符计算。也即是以每一个字体所占用的空间来计算文本范围 )
4. NSStringDrawingTruncatesLastVisibleLine (当文本不能适合的放进指定的边界之内,则自动在最后一行添加省略符号。如果NSStringDrawingUsesLineFragmentOrigin没有设置,则该选项不生效)
参数3. context: 上下文,一般传nil
使用示例
NSStringDrawingOptions options = NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading; CGRect rect = [attributeString boundingRectWithSize:CGSizeMake(label.frame.size.width, CGFLOAT_MAX) options:options context:nil];
Label富文字计算高度注意点
出现问题
当文字只有一行并且是全是中文时:高度计算不准确
解决思路
首先: 通过sizeThatFits 或 boundingWithRect 计算出未处理的rect值
第一步: 对rect值,进行判断: “是否只有一行 并且 该行文字全为中文”
第二步: 修复高度值,对高度值进行调整: “减去一个行间距值”
示例代码
//通过boundingWithRect 计算出未处理的rect值 NSStringDrawingOptions options = NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading; CGRect rect = [attributeString boundingRectWithSize:CGSizeMake(label.frame.size.width, CGFLOAT_MAX) options:options context:nil]; //判断内容是否只有一行 : (目前高度 - 字体高度) <= 行间距 if ((rect.size.height - _font.lineHeight) <= paragraphStyle.lineSpacing){ //如果只有一行,进行判断内容中是否全部为汉字 if ([self containChinese:string]) { //修正后高度为: 目前高度 - 一个行间距 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; }