iOS实录4:扩展UILabel的特性

[这是第四篇]

导语:在iOS中,有时候显示文本,需要设置文本的行间距、指定显示行数、如果文本内容超出显示行数,省略结尾部分的内容以……方式省略。这些都可以使用UILabel来是实现,前提是你扩展了UILabel这方面的特性。

——2017年4月14日

新增的特性

之前已经写过这部分内容,但是代码不简洁,使用不太方便,现在重新表述一下,思路是一样的

1、可以设置文本的显示行数。文本内容超出显示行数,结尾部分的内容以……方式省略,文本内容不超出显示行数,默认显示全部文本。
2、可以设置行间距。

一 、代码实现

1-1、新增NSString 的Size分类定义,用来计算文本占据的size#####
//  NSString+Size.h
@interface NSString (Size)

/**
 根据字体、行数、行间距和constrainedWidth计算文本占据的size

 @param font 字体
 @param numberOfLines 显示文本行数,值为0不限制行数
 @param lineSpacing 行间距
 @param constrainedWidth 文本受限的宽度
 @param isLimitedToLines 记录文本是否被numberOfLines限制
 @return 返回文本占据的size
 */
- (CGSize)textSizeWithFont:(UIFont*)font
             numberOfLines:(NSInteger)numberOfLines
               lineSpacing:(CGFloat)lineSpacing
          constrainedWidth:(CGFloat)constrainedWidth
                 isLimitedToLines:(BOOL *)isLimitedToLines;

@end
  • 将文本size的计算放到NSString的分类中,是合情合理的,之前放到UILabel的分类中,这点不太好。
  • isLimitedToLines是用来记录文本是否被numberOfLines限制,在业务中是为了控制文本的展开和收起(后面有Demo)。
1-2、NSString+Size的重要实现
- (CGSize)textSizeWithFont:(UIFont*)font
                numberOfLines:(NSInteger)numberOfLines
                  lineSpacing:(CGFloat)lineSpacing
             constrainedWidth:(CGFloat)constrainedWidth
            isLimitedToLines:(BOOL *)isLimitedToLines{

    if (self.length == 0) {
        return CGSizeZero;
    }
    CGFloat oneLineHeight = font.lineHeight;
    CGSize textSize = [self boundingRectWithSize:CGSizeMake(constrainedWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:font} context:nil].size;

    CGFloat rows = textSize.height / oneLineHeight;
    CGFloat realHeight = oneLineHeight;
    // 0 不限制行数
    if (numberOfLines == 0) {
        if (rows >= 1) {
            realHeight = (rows * oneLineHeight) + (rows - 1) * lineSpacing;
        }
    }else{
        if (rows > numberOfLines) {
            rows = numberOfLines;
            if (isLimitedToLines) {
                *isLimitedToLines = YES;  //被限制
            }
        }
        realHeight = (rows * oneLineHeight) + (rows - 1) * lineSpacing;
   }

    return CGSizeMake(constrainedWidth, realHeight);
}
2-1、新增UILabel 的FitLines分类,让文本适应于指定的行数
//  UILabel+FitLines.h
@interface UILabel (FitLines)

/**
 最大显示宽度
 */
@property (nonatomic,assign)CGFloat qsConstrainedWidth;


/**
 行间距
 */
@property (nonatomic,assign)CGFloat qsLineSpacing;


/**
 文本适应于指定的行数
 @return 文本是否被numberOfLines限制
 */
- (BOOL)qs_adjustTextToFitLines:(NSInteger)numberOfLines;

@end
  • 在初始化UILabel的时候,设置qsConstrainedWidth和qsLineSpacing,然后需要展示UILabel的内容时候,调用qs_adjustTextToFitLines就可以了,相应设置好frame就好了。
2-2、UILabel+FitLines的重要实现
- (BOOL)qs_adjustTextToFitLines:(NSInteger)numberOfLines{

    if (!self.text || self.text.length == 0) {
        return NO;
    }

    self.numberOfLines = numberOfLines;
    BOOL isLimitedToLines = NO;

    CGSize textSize = [self.text textSizeWithFont:self.font numberOfLines:self.numberOfLines lineSpacing:self.qsLineSpacing constrainedWidth:self.qsConstrainedWidth isLimitedToLines:&isLimitedToLines];

    //单行的情况
    if (fabs(textSize.height - self.font.lineHeight) < 0.00001f) {
        self.qsLineSpacing = 0.0f;
    }

    //设置文字的属性
    NSMutableAttributedString * attributedString = [[NSMutableAttributedString alloc] initWithString:self.text];

    NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    [paragraphStyle setLineSpacing:self.qsLineSpacing];
    paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;//结尾部分的内容以……方式省略
    [attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0, [self.text length])];
    [attributedString addAttribute:NSForegroundColorAttributeName value:self.textColor range:NSMakeRange(0, [self.text length])];
    [attributedString addAttribute:NSFontAttributeName value:self.font range:NSMakeRange(0, [self.text length])];

    [self setAttributedText:attributedString];
    self.bounds = CGRectMake(0, 0, textSize.width, textSize.height);
    return isLimitedToLines;
}

三、使用(初始化和显示文本)

- (UILabel *)contentLabel{

    if (!_contentLabel) {
        _contentLabel = [[UILabel alloc] init];
        _contentLabel.backgroundColor = [UIColor clearColor];
        _contentLabel.font = [UIFont systemFontOfSize:QSTextFontSize];
        _contentLabel.textColor = [UIColor blackColor];
        _contentLabel.qsConstrainedWidth = SCREEN_WIDTH - 30;
        _contentLabel.qsLineSpacing = QSTextLineSpacing;
    }
    return _contentLabel;
}

- (void)layoutSubviewsWithModel:(QSShowTextCellModel *)model{
    //...
    _contentLabel.text = model.content;
    BOOL isLimitedToLines = [_contentLabel qs_adjustTextToFitLines:model.contentLines];
    _contentLabel.frame = CGRectMake(15, CGRectGetMaxY(self.titleLabel.frame) + 10, 
                                    CGRectGetWidth( _contentLabel.bounds),CGRectGetHeight(_contentLabel.bounds));
    // ...
}
  • 其他代码见Demo

四、UILabel扩展特性的使用

  • 这个Demo是使用UITableView组织文本的显示。每一个cell可以显示title和content,cell中先指定content文本显示3行,行间距是5.0f
  • 如果content文本用3行不能全部显示,文本下面出现“显示文本”按钮,点击“显示全文”按钮,可以展开全部文本,此时按钮变成“收起全文”;点击按钮可以收起全文,依旧显示3行,按钮恢复成“显示全文”
  • 如果content文本用3行可以全部显示,不会出现按钮。
  • content显示的文本可以设置行数值,行间距值,收起全文和展开全文都是利用UILabel的扩展特性来实现的。
  • demo中使用cellModel保存cell中content显示的行数-- contentLines,通过contentlines来预先计算cell的高度。具体参见Demo源码。

** 效果图如下**

iOS实录4:扩展UILabel的特性_第1张图片
未展开全文.png
iOS实录4:扩展UILabel的特性_第2张图片
部分展开全文.png

源码直通车:QSUseLabelDemo
如果可以解决您的问题,请star一下哈

你可能感兴趣的:(iOS实录4:扩展UILabel的特性)