总结:这里实现的方式使用了numberOfLines属性,配合YYText的富文本增加点击事件,以及Masory布局来实现展开和收起,以及点击话题。
如果需要控制折叠状态下的文本字数,可以直接截取富文本的某一段就可以了,这里不赘述。
一、依赖 YYText
pod 'YYText'
二、实例化YYLabel作为文本组件
注意:要设置一下preferredMaxLayoutWidth,控制文本的宽度
(以下代码中的颜色和字体可根据自己需要自行设置,这里是使用我们自己封装的字体和颜色)
- (YYLabel *)descLabel {
if (!_descLabel) {
_descLabel = [[YYLabel alloc] init];
_descLabel.font = [DZFontStyle pingFangFontOfSize:14];
_descLabel.textColor = UIColorWithHex(@"#E0E1E6");
_descLabel.textAlignment = NSTextAlignmentLeft;
_descLabel.numberOfLines = 2;
_descLabel.lineBreakMode = NSLineBreakByTruncatingTail;
_descLabel.preferredMaxLayoutWidth = CONTAINER_WIDTH;
}
return _descLabel;
}
三、获取富文本
1.第一步就是将整个的普通字符串,添加字体、颜色属性成富文本,再链接append上话题的富文本,形成了一个完整的富文本;
2.这一步需要设置展开状态下的富文本:
普通字符串富文本 + #话题#富文本及点击事件 + 省略号...(可选,这里我使用了空格) + “收起”image及点击事件
3.折叠状态下的富文本,就是完整的富文本;(折叠状态下显示“展开”的操作在下一节)
4.避免重复计算展开和折叠状态下的富文本,所以使用2个变量接收第一次算出来的富文本
5.在label所在的代码作用域,实现“收起”的点击事件(下面代码是用block交给外层)
/// 处理图片描述富文本
- (NSAttributedString *)videoLayerDescAttStrWithDescWidth:(CGFloat)descWidth {
// 普通字符串
NSString *allStr = DZRealString(self.videoInfoVO.des);
// 富文本
NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:allStr];
NSRange range = NSMakeRange(0, attStr.length);
if (range.location != NSNotFound) {
[attStr addAttribute:NSFontAttributeName value:Font(14) range:range];
[attStr addAttribute:NSForegroundColorAttributeName value:UIColorFromRGB(0xE0E1E6) range:range];
}
//话题,如果存在,添加点击方法(这里使用block交给外部实现),就append起来
NSString *topicStr = nil;
NSMutableAttributedString *topicAttStr = nil;
if (!IsEmpty(self.topicInfoVO)) {
topicStr = [NSString stringWithFormat:@"#%@#", DZRealString(self.topicInfoVO.title)];
topicAttStr = [[NSMutableAttributedString alloc] initWithString:topicStr attributes:@{NSFontAttributeName:[DZFontStyle pingFangMediumFontOfSize:14], NSForegroundColorAttributeName:UIColorFromRGB(0xFFFFFF)}];
@weakify_dzx(self);
[topicAttStr yy_setTextHighlightRange:NSMakeRange(0, topicAttStr.length) color:UIColorFromRGB(0xFFFFFF) backgroundColor:[UIColor clearColor] tapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) {
@strongify_dzx(self);
if (self.topicClick) {
self.topicClick();
}
}];
[attStr appendAttributedString:topicAttStr];
}
// 这里是2行的宽度,减去"收起"图片的宽度,就是展示整个富文本的总宽度
CGFloat descTwoLineMaxWidth = descWidth * 2.0 - 35;
// 富文本需要展示完全的宽度
CGRect fullStrRectInOneLine = [attStr boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) context:nil];
if (fullStrRectInOneLine.size.width > descTwoLineMaxWidth) { // 超出2行 折叠起来了
if (self.isExpand) {
if (self.expandDescAttri) {
return self.expandDescAttri;
} else {
// 这里控制的是,让"展开"状态下的富文本最多字数为100,
if (attStr.length > 100) {
attStr = [[NSMutableAttributedString alloc] initWithAttributedString:[attStr attributedSubstringFromRange:NSMakeRange(0, 100)]];
}
// append 空格
[attStr appendAttributedString:[[NSAttributedString alloc] initWithString:@" " attributes:@{NSForegroundColorAttributeName : [UIColor whiteColor], NSFontAttributeName : Font(14)}]];
// append "收起"图片的attachment
NSAttributedString *imgAttri = [NSAttributedString yy_attachmentStringWithContent:[UIImage imageNamed:@"immersion_video_desc_collapse"] contentMode:UIViewContentModeCenter attachmentSize:CGSizeMake(35, 16) alignToFont:[DZFontStyle pingFangFontOfSize:16] alignment:(YYTextVerticalAlignmentCenter)];
[attStr appendAttributedString:imgAttri];
// 点击"收起"的事件
@weakify_dzx(self);
NSRange attachmentRange = NSMakeRange(attStr.length - 1, 1);
[attStr yy_setTextHighlightRange:attachmentRange color:nil backgroundColor:nil tapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) {
@strongify_dzx(self);
if (self.videoCollapseClick) {
self.videoCollapseClick();
}
}];
// 拼接成最终的富文本
attStr = [[NSMutableAttributedString alloc] initWithAttributedString:[[self class] addParagraphForAttri:attStr]];
self.expandDescAttri = attStr;
return attStr;
}
} else {
if (self.foldDescAttri) {
return self.foldDescAttri;
} else {
// 完整的富文本
attStr = [[NSMutableAttributedString alloc] initWithAttributedString:[[self class] addParagraphForAttri:attStr]];
self.foldDescAttri = attStr;
return attStr;
}
}
} else { // 未超出2行
return attStr;
}
return attStr;
}
// 这里加了富文本的行间距属性
+ (NSAttributedString *)addParagraphForAttri:(NSAttributedString *)attStr {
NSRange attRange = NSMakeRange(0, attStr.length);
if (attRange.location != NSNotFound) {
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineSpacing = 5;
paragraphStyle.paragraphSpacing = 0;
paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
NSMutableAttributedString *attributedStr = [[NSMutableAttributedString alloc] initWithAttributedString:attStr];
[attributedStr addAttributes:@{ NSParagraphStyleAttributeName : paragraphStyle} range:attRange];
return attributedStr;
}
return attStr;
}
- 收起事件的实现
// "收起"
infoVo.videoCollapseClick = ^{
weakSelf.infoVo.isExpand = NO;
weakSelf.descLabel.numberOfLines = 2;
weakSelf.descLabel.attributedText = [weakSelf.infoVo videoLayerDescAttStrWithDescWidth:CONTAINER_WIDTH];
};
四、折叠状态下的“展开”+ 点击展开事件
- 使用YYLabel的truncationToken,来显示“展开”。
// 这里使用变量属性truncationToken,后面会赋值给YYLabel
- (NSAttributedString *)truncationToken{
if (!_truncationToken) {
// 展开图片的size
CGSize imageSize = CGSizeMake(57, 27);
// 容器view,子视图是省略号+展开image
UIView *trailingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, imageSize.width, imageSize.height)];
// 给容器视图加点击事件,点击后就显示展开状态下的富文本
@weakify_dzx(self);
[trailingView addTapGestureActionWithBlock:^(UITapGestureRecognizer * _Nonnull tapAction) {
@strongify_dzx(self);
[self tapExpandAction];
}];
// 省略号
UILabel *dotLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 6, 22, 17)];
dotLabel.font = [DZFontStyle pingFangFontOfSize:14];
dotLabel.textColor = [UIColor whiteColor];
dotLabel.text = @"...";
// 展开image
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"immersion_video_desc_expand"]];
imageView.frame = CGRectMake(22, 6, 35, 16);
// 添加进容器
[trailingView addSubview:dotLabel];
[trailingView addSubview:imageView];
_truncationToken = [NSAttributedString yy_attachmentStringWithContent:trailingView contentMode:UIViewContentModeCenter attachmentSize:imageSize alignToFont:[DZFontStyle pingFangFontOfSize:16] alignment:(YYTextVerticalAlignmentCenter)];
}
return _truncationToken;
}
- 赋值truncationToken
self.descLabel.truncationToken = self.truncationToken;
- 展开的实现
/// 点击展开
- (void)tapExpandAction {
self.infoVo.isExpand = YES;
self.descLabel.numberOfLines = 0; // 不限行
self.descLabel.attributedText = [self.infoVo videoLayerDescAttStrWithDescWidth:CONTAINER_WIDTH];
}
五、给YYLabel赋值
// 描述
self.descLabel.attributedText = [infoVo videoLayerDescAttStrWithDescWidth:CONTAINER_WIDTH];