看图说话比较清晰,点击红色标记的区域,会展开全文。
相关知识点
- 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 clusteras the values for touchable highlight attributes (stored in the attributed stringunder 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;