iOS使用YYLabel 点击展开和收起全文
程序员文章站
2024-03-24 13:12:40
...
看图说话比较清晰,点击红色标记的区域,会展开全文。
相关知识点
- YYLabel,truncationToken
- NSAttributedString,YYText,YYTextHighlight
我们来看一下YYLabel的属性truncationToken,是一个富文本,当Label被截断时,该富文本显示在文末,默认与UILabel显示的一样,是三个点。
/**
The truncation token string used when text is truncated. Default is nil.
When the value is nil, the label use "…" as default truncation token.
*/
@property (nullable, nonatomic, copy) NSAttributedString *truncationToken;
我们可以使用以下方式来指定切断文本:
YYLabel *label = [YYLabel new];
lable.text = @"我们可以使用以下方式来指定切断文本";
NSAttributedString *truncationToken = [[NSAttributedString alloc] initWithString:@"… 展开"]];
label.truncationToken = truncationToken;
接着来了解一下实现点击响应事件的YYTextHighlight 和 tapAction
/**
YYTextHighlight objects are used by the NSAttributedString class cluster
as the values for touchable highlight attributes (stored in the attributed string
under the key named YYTextHighlightAttributeName).
When display an attributed string in `YYLabel` or `YYTextView`, the range of
highlight text can be toucheds down by users. If a range of text is turned into
highlighted state, the `attributes` in `YYTextHighlight` will be used to modify
(set or remove) the original attributes in the range for display.
*/
@interface YYTextHighlight : NSObject <NSCoding, NSCopying>
在YYLabel或者YYTextView的富文本中,指定YYTextHighlight的范围,用户就可以在该范围内实现点击效果。
/**
The tap/long press action callback defined in YYText.
@param containerView The text container view (such as YYLabel/YYTextView).
@param text The whole text.
@param range The text range in `text` (if no range, the range.location is NSNotFound).
@param rect The text frame in `containerView` (if no data, the rect is CGRectNull).
*/
typedef void(^YYTextAction)(UIView *containerView, NSAttributedString *text, NSRange range, CGRect rect);
/**
Tap action when user tap the highlight, default is nil.
If the value is nil, YYTextView or YYLabel will ask it's delegate to handle the tap action.
*/
@property (nullable, nonatomic, copy) YYTextAction tapAction;
tapAction是一个block回调,在用户点击highlight时会触发。如果没有指定tapAction, 点击会使用delegate的方式触发。
//添加点击事件
YYTextHighlight *hi = [YYTextHighlight new];
[text yy_setTextHighlight:hi range:[text.string rangeOfString:moreString]];
hi.tapAction = ^(UIView *containerView, NSAttributedString *text, NSRange range, CGRect rect) {
//这里是自己的代码
};
最终的代码
- (YYLabel *)tokenLabel {
if (!_tokenLabel) {
_tokenLabel = [YYLabel new];
_tokenLabel.frame = CGRectMake(20, 100, [UIScreen mainScreen].bounds.size.width - 40, 30);
_tokenLabel.numberOfLines = 0;
_tokenLabel.backgroundColor = [UIColor colorWithWhite:0.5 alpha:0.75];
[self addSeeMoreButtonInLabel:_tokenLabel];
}
return _tokenLabel;
}
- (void)addSeeMoreButtonInLabel:(YYLabel *)label {
UIFont *font16 = [UIFont systemFontOfSize:16];
label.attributedText = [[NSAttributedString alloc] initWithString:@"我们可以使用以下方式来指定切断文本; 收起 我们可以使用以下方式来指定切断文本" attributes:@{NSFontAttributeName : font16}];
NSString *moreString = @" 展开";
NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"... %@", moreString]];
NSRange expandRange = [text.string rangeOfString:moreString];
[text addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:expandRange];
[text addAttribute:NSForegroundColorAttributeName value:[UIColor darkTextColor] range:NSMakeRange(0, expandRange.location)];
//添加点击事件
YYTextHighlight *hi = [YYTextHighlight new];
[text yy_setTextHighlight:hi range:[text.string rangeOfString:moreString]];
__weak typeof(self) weakSelf = self;
hi.tapAction = ^(UIView *containerView, NSAttributedString *text, NSRange range, CGRect rect) {
//点击展开
[weakSelf setFrame:YES];
};
text.yy_font = font16;
YYLabel *seeMore = [YYLabel new];
seeMore.attributedText = text;
[seeMore sizeToFit];
NSAttributedString *truncationToken = [NSAttributedString yy_attachmentStringWithContent:seeMore contentMode:UIViewContentModeCenter attachmentSize:seeMore.frame.size alignToFont:text.yy_font alignment:YYTextVerticalAlignmentTop];
label.truncationToken = truncationToken;
}
- (NSAttributedString *)appendAttriStringWithFont:(UIFont *)font {
if (!font) {
font = [UIFont systemFontOfSize:16];
}
if ([_tokenLabel.attributedText.string containsString:@"收起"]) {
return [[NSAttributedString alloc] initWithString:@""];
}
NSString *appendText = @" 收起 ";
NSMutableAttributedString *append = [[NSMutableAttributedString alloc] initWithString:appendText attributes:@{NSFontAttributeName : font, NSForegroundColorAttributeName : [UIColor blueColor]}];
YYTextHighlight *hi = [YYTextHighlight new];
[append yy_setTextHighlight:hi range:[append.string rangeOfString:appendText]];
__weak typeof(self) weakSelf = self;
hi.tapAction = ^(UIView *containerView, NSAttributedString *text, NSRange range, CGRect rect) {
//点击收起
[weakSelf setFrame:NO];
};
return append;
}
- (void)expandString {
NSMutableAttributedString *attri = [_tokenLabel.attributedText mutableCopy];
[attri appendAttributedString:[self appendAttriStringWithFont:attri.yy_font]];
_tokenLabel.attributedText = attri;
}
- (void)packUpString {
NSString *appendText = @" 收起 ";
NSMutableAttributedString *attri = [_tokenLabel.attributedText mutableCopy];
NSRange range = [attri.string rangeOfString:appendText options:NSBackwardsSearch];
if (range.location != NSNotFound) {
[attri deleteCharactersInRange:range];
}
_tokenLabel.attributedText = attri;
}
- (void)setFrame:(BOOL)isExpand {
if (isExpand) {
[self expandString];
self.tokenLabel.frame = CGRectMake(20, 100, [UIScreen mainScreen].bounds.size.width - 40, 200);
}
else {
[self packUpString];
self.tokenLabel.frame = CGRectMake(20, 100, [UIScreen mainScreen].bounds.size.width - 40, 30);
}
}
如果需要用UIImage或者UIView等用作truncationToken,可以用以下方法转换成富文本。
使用这个方法可以把UIImage/UIView/CALayer转换成富文本的方式。
+ (NSMutableAttributedString *)yy_attachmentStringWithContent: contentMode: attachmentSize: alignToFont: alignment:
如果没有把text放到YYLabel里面,而是直接赋值给truncationToken是不会有点击事件的。如下:
//添加点击事件
YYTextHighlight *hi = [YYTextHighlight new];
[text yy_setTextHighlight:hi range:[text.string rangeOfString:moreString]];
hi.tapAction = ^(UIView *containerView, NSAttributedString *text, NSRange range, CGRect rect) {
//这里是自己的代码
};
label.truncationToken = text;