在 B 站的 up 主动态页面中,如果文本的动态内容超过四行,剩下的内容就会被隐藏,末尾会有一个展开按钮。
展开文本内容后,内容的末尾会有一个收起按钮,可以还原到原来的状态。
我们可以使用 YYText 框架,实现多行文本的展开/收起逻辑。
这是我需要展示的一段文本内容:
Hero 9 Black 的感光器升级到 20MP,让它可以录影最多 5K 30p 的视频,并保留 4K 60p 和 2.7K 240p 的高流畅度录影能力。\nHero 9 Black 的电池容量为 1,720mAh,比上一代提升 30%,且在低温环境下的性能提高。\n内置地平线修正功能,支持 30 秒视频预录,定时拍摄、限时拍摄、实况照片多种模式。还可实现 1080P 视频直播。
默认情况下,假设我的页面最多只能显示三行文本,超出的部分截断不显示。我通过 YYLabel
实现这个 Label 标签:
首先,在当前视图控制器页面中,导入 <YYKit>
框架,你也可以根据需要只导入 <YYLabel>
框架。
#import <YYKit.h>
然后将 YYLabel
声明为当前视图控制器下的属性:
@interface TestViewController ()
@property (nonatomic, strong) YYLabel *textLabel;
@end
创建并添加 YYLabel
到当前页面中:
- (void)addYYLabel {
self.textLabel = [[YYLabel alloc] init];
NSString *string = @"Hero 9 Black 的感光器升级到 20MP,让它可以录影最多 5K 30p 的视频,并保留 4K 60p 和 2.7K 240p 的高流畅度录影能力。\nHero 9 Black 的电池容量为 1,720mAh,比上一代提升 30%,且在低温环境下的性能提高。\n内置地平线修正功能,支持 30 秒视频预录,定时拍摄、限时拍摄、实况照片多种模式。还可实现 1080P 视频直播。";
self.textLabel.text = string;
self.textLabel.font = [UIFont systemFontOfSize:17.0f];
self.textLabel.textColor = [UIColor blackColor];
self.textLabel.numberOfLines = 0;
self.textLabel.textVerticalAlignment = YYTextVerticalAlignmentTop;
self.textLabel.frame = CGRectMake(0, 0, kScreenWidth - 20, 63);
self.textLabel.center = self.view.center;
[self.view addSubview:self.textLabel];
}
接下来就是,...展开
按钮的实现。首先,...展开
也是一个 YYLabel
,我们把这个 YYLabel
设置为整个标签的的truncationToken
截断符即可。
YYLabel
有一个 truncationToken
属性,如果不设置,就是默认的 ...
。
@property (nullable, nonatomic, copy) NSAttributedString *truncationToken;
...展开
标签的实现如下:
// MARK: 创建一个有展开/收起按钮的 YYLabel
- (void)addYYLabel {
// 创建并添加 YYLabel ...
// 创建属性字符串"...展开"
NSMutableAttributedString *expandString = [[NSMutableAttributedString alloc] initWithString:@"...展开"];
expandString.font = self.textLabel.font;
NSRange highlightRange = [expandString.string rangeOfString:@"展开"];
[expandString setColor:[UIColor colorWithRed:0.000 green:0.449 blue:1.000 alpha:1.000]
range:highlightRange];
// 创建一个“高亮”属性
YYTextHighlight *highlight = [YYTextHighlight new];
[highlight setFont:self.textLabel.font];
[highlight setColor:[UIColor colorWithRed:0.578 green:0.790 blue:1.000 alpha:1.000]];
// !!!: 点击「展开」按钮,执行的动作
highlight.tapAction = ^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) {
// TODO: 点击展开按钮后,完整显示所有内容
[self.textLabel sizeToFit];
};
[expandString setTextHighlight:highlight range:highlightRange];
// 将属性字符串设置到 YYLabel 中
YYLabel *expandLabel = [[YYLabel alloc] init];
expandLabel.attributedText = expandString;
[expandLabel sizeToFit];
// 将此带高亮属性的 YYLabel 设置为整个 YYLabel 的截断符
NSAttributedString *truncationToken = [NSAttributedString attachmentStringWithContent:expandLabel contentMode:UIViewContentModeCenter attachmentSize:expandLabel.size alignToFont:expandString.font alignment:YYTextVerticalAlignmentCenter];
self.textLabel.truncationToken = truncationToken;
}
...展开
字符串是一个 NSMutableAttributedString
类型的属性字符串,我在上面附着了点击高亮效果、支持点击执行 Block 代码。
然后,通过该属性字符串重新创建一个新的 YYLabel
实例对象。
最后,将该 YYLabel
实例对象设置为整个 YYLabel的截断符,当文本字符串无法完整显示所有内容时,它就会自动显示
...展开`。
接下来,我们继续实现显示完整内容时的“收起”功能。
“收起” 功能其实很简单,当完全显示所有内容时,就是在整个文本末尾 appendAttributedString:
一个内容为“收起”的属性字符串。
设置文本内容为“收起”的属性字符串:
// 创建属性字符串“收起”
NSMutableAttributedString *collapseString = [[NSMutableAttributedString alloc] initWithString:@"收起"];
collapseString.font = self.textLabel.font;
collapseString.color = [UIColor colorWithRed:0.000 green:0.449 blue:1.000 alpha:1.000];
// 创建一个“高亮属性”
YYTextHighlight *highlight = [YYTextHighlight new];
[highlight setFont:self.textLabel.font];
[highlight setColor:[UIColor colorWithRed:0.578 green:0.790 blue:1.000 alpha:1.000]];
// !!!: 点击「收起」按钮,执行的动作
__weak __typeof(self)weakSelf = self;
highlight.tapAction = ^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
// 点击“收起”文本后,重新设置 YYLabel 的尺寸
strongSelf.textLabel.frame = CGRectMake(0, 0, kScreenWidth - 20, 63);
strongSelf.textLabel.center = self.view.center;
// 别忘了,重设整个文本字符串
};
[collapseString setTextHighlight:highlight range:collapseString.rangeOfAll];
源码见 GitHub 源码