开源代码信息
YYText的使用

YYLabel特性介绍

YYLabel 是一个只读TextView,它除了具备UILabel所必备的特性外,还支持如下特性:

* 支持异步布局和渲染,避免阻塞UI线程
* 通过扩展CoreText属性来支持更多的文本特效
* 允许文本和UIImage, UIView 和 CALayer 进行图文混排
* 允许添加局部用户可交互的高亮链接
* 允许添加和移除container路径来控制文本container的形状
* 支持纵向布局显示文本

YYTextView特性介绍

和YYLabel不同的是YYTextView是一个可滚动的,可编辑(当然也可以设置为不可编辑)多行文本控件。

* 通过扩展CoreText属性来支持更多的文本特效
* 允许文本和UIImage, UIView 和 CALayer 进行图文混排
* 允许添加局部用户可交互的高亮链接
* 允许添加和移除container路径来控制文本container的形状
* 支持纵向布局显示文本
* 允许用户在text view之间复制图像和富文本
* 可以将属性文本作为占位文本

YYLabel/YYTextView 常用属性

/**
显示在label上的文本,它和attributedText是互斥的,一旦设置了attributedText 就会覆盖 text
*/
@property (nullable, nonatomic, copy) NSString *text;

/**
text的文本字体,也会影响到attributedText
*/
@property (null_resettable, nonatomic, strong) UIFont *font;

/**
text的颜色,默认是黑色,这个值的设置也会影响到attributedText
*/
@property (null_resettable, nonatomic, strong) UIColor *textColor;

/**
text文本阴影的颜色,这个值的设置也会影响到attributedText
*/
@property (nullable, nonatomic, strong) UIColor *shadowColor;

/**
阴影的偏移,默认是CGSizeZero,这个值的设置也会影响到attributedText
*/
@property (nonatomic) CGSize shadowOffset;

/**
text 阴影模糊半径,默认为0,这个值的设置也会影响到attributedText
*/
@property (nonatomic) CGFloat shadowBlurRadius;

/**
text的对齐方式
*/
@property (nonatomic) NSTextAlignment textAlignment;

/**
垂直对齐方式
*/
@property (nonatomic) YYTextVerticalAlignment textVerticalAlignment;

/**
属性文本内容
*/
@property (nullable, nonatomic, copy) NSAttributedString *attributedText;

/**
断行模式
*/
@property (nonatomic) NSLineBreakMode lineBreakMode;

/**
在文本被截断的时候,作为截断文本的字符串,默认为“...”
*/
@property (nullable, nonatomic, copy) NSAttributedString *truncationToken;

/**
最大文本行数
*/
@property (nonatomic) NSUInteger numberOfLines;

/**
多行文本的推荐宽度,如果文本的宽度超过这个设定值,文本内容将会显示到新的一行或者多行,所以会增加整个文本的高度。
*/
@property (nonatomic) CGFloat preferredMaxLayoutWidth;


/**
可以点击的修饰样式

UIDataDetectorTypePhoneNumber 手机号码
UIDataDetectorTypeLink URL链接
UIDataDetectorTypeAddress 地址
UIDataDetectorTypeCalendarEvent 日历事件
UIDataDetectorTypeShipmentTrackingNumber 船舶跟踪号码
UIDataDetectorTypeFlightNumber 航空号码
UIDataDetectorTypeLookupSuggestion 用户查询建议
UIDataDetectorTypeNone 无修饰样式
UIDataDetectorTypeAll 全部样式
*/
@property (nonatomic) UIDataDetectorTypes dataDetectorTypes;

/**
* 用于修改dataDetectorTypes的样式
*/
@property (nullable, nonatomic, copy) NSDictionary<NSString *, id> *linkTextAttributes;


/**
* 高亮文本样式
*/
@property (nullable, nonatomic, copy) NSDictionary<NSString *, id> *highlightTextAttributes;

/**
* 用户新输入的文本属性
*/
@property (nullable, nonatomic, copy) NSDictionary<NSString *, id> *typingAttributes;

/**
占位文本
*/
@property (nullable, nonatomic, copy) NSString *placeholderText;

/**
占位文本字体
*/
@property (nullable, nonatomic, strong) UIFont *placeholderFont;

/**
占位文本颜色
*/
@property (nullable, nonatomic, strong) UIColor *placeholderTextColor;

/**
占位文本富文本属性
*/
@property (nullable, nonatomic, copy) NSAttributedString *placeholderAttributedText;


/**
当前选择的Range
*/
@property (nonatomic) NSRange selectedRange;

/**
* 插入的文本是否替换旧有的内容
*/
@property (nonatomic) BOOL clearsOnInsertion;

/**
能否选择文本,编辑文本
*/
@property (nonatomic, getter=isSelectable) BOOL selectable;

/**
是否可以高亮文本
*/
@property (nonatomic, getter=isHighlightable) BOOL highlightable;

/**
是否可编辑
*/
@property (nonatomic, getter=isEditable) BOOL editable;

/**
是否允许粘贴图片
*/
@property (nonatomic) BOOL allowsPasteImage;

/**
是否允许粘贴富文本
*/
@property (nonatomic) BOOL allowsPasteAttributedString;

/**
是否允许复制富文本
*/
@property (nonatomic) BOOL allowsCopyAttributedString;

/**
是否允许重做和撤销
*/
@property (nonatomic) BOOL allowsUndoAndRedo;

/**
撤销步骤数
*/
@property (nonatomic) NSUInteger maximumUndoLevel;


/**
* 在textview获得焦点的时候取代系统键盘的自定义输入view
*/
@property (nullable, nonatomic, readwrite, strong) __kindof UIView *inputView;

/**
*
* 在textview获得焦点的时候显示在键盘上方的附加view
*/
@property (nullable, nonatomic, readwrite, strong) __kindof UIView *inputAccessoryView;

/**
* 如果不使用inputAccessoryView属性指定自定义附加view,可以使用它来指定附加view的高度
*/
@property (nonatomic) CGFloat extraAccessoryViewHeight;

一些交互事件

/**
点击文本的时候响应Block
*/
@property (nullable, nonatomic, copy) YYTextAction textTapAction;
/**
长按文本的时候响应的Block
*/
@property (nullable, nonatomic, copy) YYTextAction textLongPressAction;
/**
* 点击高亮文本的时候执行的动作
*/
@property (nullable, nonatomic, copy) YYTextAction highlightTapAction;
/**
* 长按高亮文本时候执行的动作
*/
@property (nullable, nonatomic, copy) YYTextAction highlightLongPressAction;

/**
文本内间距
*/
@property (nonatomic) UIEdgeInsets textContainerInset;

高级用法

/**
用于控制布局和渲染代码是否运行在后台线程,默认是不运行在后台线程
*/
@property (nonatomic) BOOL displaysAsynchronously;

/**
当异步显示打开的情况下,在后台渲染进程结束后,layer的内容将会更新,但是如果渲染进程在一个垂直同步时间内
不能完成渲染工作,将会保持显示显示旧的内容。我们可以在更新label属性后通过手动将layer.contents设置为nil,或者将这个值设置为YES.

*/
@property (nonatomic) BOOL clearContentsBeforeAsynchronouslyDisplay;

/**
在文本内容发生改变的时候会有一个动画
*/
@property (nonatomic) BOOL fadeOnAsynchronouslyDisplay;

/**
在某些文本高亮的时候呈现一个动画
*/
@property (nonatomic) BOOL fadeOnHighlight;

/**
忽略text, font, textColor, attributedText...这些通用的属性,只使用textLayout来显示文本内容
*/
@property (nonatomic) BOOL ignoreCommonProperties;

YYText中给定的建议如下:

1. If you only need a UILabel alternative to display rich text and receive link touch event, 
you do not need to adjust the display mode properties.

如果你只想要作为UILabel来显示富文本或者接受链接点击事件,我们不需要设置上面的显示模式属性。

2. If you have performance issues, you may enable the asynchronous display mode
by setting the `displaysAsynchronously` to YES.

如果我们遇到了性能问题需要提高文本的显示性能,那么可以将displaysAsynchronously设置为YES使用异步显示模式

3. If you want to get the highest performance, you should do text layout with
`YYTextLayout` class in background thread. Here's an example:

如果我们想获得最高的性能,我们需要在后台使用YYTextLayout来做布局

异步绘制会在后面给出例子:

1. 属性文本

属性文本样式设置大家可以查看NSAttributedString+YYText.h文件,我们用得比较多的是NSMutableAttributedString,下面只列出用得比较多的,大家使用的时候可以查看NSAttributedString+YYText.h:

基本文本属性:

/**
设置全部文本的样式
*/
- (void)yy_setAttribute:(NSString *)name value:(nullable id)value;

/**
设置指定范围的文本样式
*/
- (void)yy_setAttribute:(NSString *)name value:(nullable id)value range:(NSRange)range;

/**
The font of the text.
*/
@property (nullable, nonatomic, strong, readwrite) UIFont *yy_font;
- (void)yy_setFont:(nullable UIFont *)font range:(NSRange)range;

/**
The foreground color.
*/
@property (nullable, nonatomic, strong, readwrite) UIColor *yy_color;
- (void)yy_setColor:(nullable UIColor *)color range:(NSRange)range;

/**
The background color.
*/
@property (nullable, nonatomic, strong, readwrite) UIColor *yy_backgroundColor;
- (void)yy_setBackgroundColor:(nullable UIColor *)backgroundColor range:(NSRange)range;

/**
The stroke width.
*/
@property (nullable, nonatomic, strong, readwrite) NSNumber *yy_strokeWidth;
- (void)yy_setStrokeWidth:(nullable NSNumber *)strokeWidth range:(NSRange)range;

/**
The stroke color.
*/
@property (nullable, nonatomic, strong, readwrite) UIColor *yy_strokeColor;
- (void)yy_setStrokeColor:(nullable UIColor *)strokeColor range:(NSRange)range;

/**
The text shadow.
*/
@property (nullable, nonatomic, strong, readwrite) NSShadow *yy_shadow;
- (void)yy_setShadow:(nullable NSShadow *)shadow range:(NSRange)range;

/**
The strikethrough style.
*/
@property (nonatomic, readwrite) NSUnderlineStyle yy_strikethroughStyle;
- (void)yy_setStrikethroughStyle:(NSUnderlineStyle)strikethroughStyle range:(NSRange)range;

/**
The strikethrough color.
*/
@property (nullable, nonatomic, strong, readwrite) UIColor *yy_strikethroughColor;
- (void)yy_setStrikethroughColor:(nullable UIColor *)strikethroughColor range:(NSRange)range NS_AVAILABLE_IOS(7_0);

/**
The underline style.
*/
@property (nonatomic, readwrite) NSUnderlineStyle yy_underlineStyle;
- (void)yy_setUnderlineStyle:(NSUnderlineStyle)underlineStyle range:(NSRange)range;

/**
The underline color.
*/
@property (nullable, nonatomic, strong, readwrite) UIColor *yy_underlineColor;
- (void)yy_setUnderlineColor:(nullable UIColor *)underlineColor range:(NSRange)range;

段落属性


/**
An NSParagraphStyle object which is used to specify things like
line alignment, tab rulers, writing direction, etc.
*/
@property (nullable, nonatomic, strong, readwrite) NSParagraphStyle *yy_paragraphStyle;
- (void)yy_setParagraphStyle:(nullable NSParagraphStyle *)paragraphStyle range:(NSRange)range;

/**
* 文本对齐方式
*/
@property (nonatomic, readwrite) NSTextAlignment yy_alignment;
- (void)yy_setAlignment:(NSTextAlignment)alignment range:(NSRange)range;

/**
* 断行模式
*/
@property (nonatomic, readwrite) NSLineBreakMode yy_lineBreakMode;
- (void)yy_setLineBreakMode:(NSLineBreakMode)lineBreakMode range:(NSRange)range;

/**
行间距
*/
@property (nonatomic, readwrite) CGFloat yy_lineSpacing;
- (void)yy_setLineSpacing:(CGFloat)lineSpacing range:(NSRange)range;

/**
段落间距
*/
@property (nonatomic, readwrite) CGFloat yy_paragraphSpacing;
- (void)yy_setParagraphSpacing:(CGFloat)paragraphSpacing range:(NSRange)range;

/**
段落前间距
*/
@property (nonatomic, readwrite) CGFloat yy_paragraphSpacingBefore;
- (void)yy_setParagraphSpacingBefore:(CGFloat)paragraphSpacingBefore range:(NSRange)range;

/**
首行间距
*/
@property (nonatomic, readwrite) CGFloat yy_firstLineHeadIndent;
- (void)yy_setFirstLineHeadIndent:(CGFloat)firstLineHeadIndent range:(NSRange)range;

/**
最小高度
*/
@property (nonatomic, readwrite) CGFloat yy_minimumLineHeight;
- (void)yy_setMinimumLineHeight:(CGFloat)minimumLineHeight range:(NSRange)range;

/**
最大高度
*/
@property (nonatomic, readwrite) CGFloat yy_maximumLineHeight;
- (void)yy_setMaximumLineHeight:(CGFloat)maximumLineHeight range:(NSRange)range;

简单的一个例子:

 //1.创建一个属性文本
NSMutableAttributedString *attributeStr = [[NSMutableAttributedString alloc] initWithString:@"测试文本,测试文本测试文本测试文本测试文本测试文本测试文本测试文本"];

//2.为文本设置属性
attributeStr.yy_font = [UIFont boldSystemFontOfSize:18.0];
[attributeStr yy_setColor:[UIColor blueColor] range:NSMakeRange(0, 50)];
attributeStr.yy_lineSpacing = 20.0;

//3.赋值给YYLabel
YYLabel *yyLabel = [[YYLabel alloc] init];
yyLabel.attributedText = attributeStr;
yyLabel.numberOfLines = 0;
yyLabel.frame = CGRectMake(0.0, 0.0, self.view.bounds.size.width, 400.0);
[self.view addSubview:yyLabel];

2. 文本高亮

使用YYText还可以为某些文本指定高亮文本样式,默认的是浅蓝色的文本,如果是常见的比如电话号码之类的可以使用UIDataDetectorTypes来快速指定,但是如果是自定义的则可以有两种方式可以指定高亮文本:
一种是通过yy_setTextHighlightRange来指定,但是这种方式能设置的样式比较有限,只能设置前景色和背景色,但是对于一般的需求是足够用了:

/**
Convenience method to set text highlight
@param range text range
@param color text color (pass nil to ignore)
@param backgroundColor text background color when highlight
@param userInfo user information dictionary (pass nil to ignore)
@param tapAction tap action when user tap the highlight (pass nil to ignore)
@param longPressAction long press action when user long press the highlight (pass nil to ignore)
*/
- (void)yy_setTextHighlightRange:(NSRange)range
color:(nullable UIColor *)color
backgroundColor:(nullable UIColor *)backgroundColor
userInfo:(nullable NSDictionary *)userInfo
tapAction:(nullable YYTextAction)tapAction
longPressAction:(nullable YYTextAction)longPressAction;

另一种是借助YYTextHighlight,下面是YYTextHighlight所能设置的属性:

+ (instancetype)highlightWithBackgroundColor:(nullable UIColor *)color;
- (void)setFont:(nullable UIFont *)font;
- (void)setColor:(nullable UIColor *)color;
- (void)setStrokeWidth:(nullable NSNumber *)width;
- (void)setStrokeColor:(nullable UIColor *)color;
- (void)setShadow:(nullable YYTextShadow *)shadow;
- (void)setInnerShadow:(nullable YYTextShadow *)shadow;
- (void)setUnderline:(nullable YYTextDecoration *)underline;
- (void)setStrikethrough:(nullable YYTextDecoration *)strikethrough;
- (void)setBackgroundBorder:(nullable YYTextBorder *)border;
- (void)setBorder:(nullable YYTextBorder *)border;
- (void)setAttachment:(nullable YYTextAttachment *)attachment;
@property (nullable, nonatomic, copy) YYTextAction tapAction;
@property (nullable, nonatomic, copy) YYTextAction longPressAction;

这里涉及到了YYTextBorder,它其实就是一个文本的外框,可以给选中的文本添加外框样式:

@interface YYTextBorder : NSObject <NSCoding, NSCopying>
+ (instancetype)borderWithLineStyle:(YYTextLineStyle)lineStyle lineWidth:(CGFloat)width strokeColor:(nullable UIColor *)color;
+ (instancetype)borderWithFillColor:(nullable UIColor *)color cornerRadius:(CGFloat)cornerRadius;
@property (nonatomic) YYTextLineStyle lineStyle; ///< border line style
@property (nonatomic) CGFloat strokeWidth; ///< border line width
@property (nullable, nonatomic, strong) UIColor *strokeColor; ///< border line color
@property (nonatomic) CGLineJoin lineJoin; ///< border line join
@property (nonatomic) UIEdgeInsets insets; ///< border insets for text bounds
@property (nonatomic) CGFloat cornerRadius; ///< border corder radius
@property (nullable, nonatomic, strong) YYTextShadow *shadow; ///< border shadow
@property (nullable, nonatomic, strong) UIColor *fillColor; ///< inner fill color
@end

简单的例子:

//1.创建一个属性文本
NSMutableAttributedString *attributeStr = [[NSMutableAttributedString alloc] initWithString:@"旧时月色,算几番照我,梅边吹笛?唤起玉人,不管清寒与攀摘.何逊而今渐老,都忘却,春风词笔.但怪得,竹外疏花,春冷入瑶席.江国,正寂寂.叹寄与路遥,夜雪初积.翠尊易泣,红萼无言耿相忆.常记曾携手处,千树压.梅湖寒碧,又片片吹尽也,何时得见? "];

//2.为文本设置属性
attributeStr.yy_font = [UIFont boldSystemFontOfSize:18.0];
attributeStr.yy_lineSpacing = 20.0;

//3.创建高亮属性
YYTextBorder *border = [YYTextBorder borderWithFillColor:[UIColor magentaColor] cornerRadius:4];

YYTextHighlight *highlight = [[YYTextHighlight alloc] init];
[highlight setColor:[UIColor blueColor]];
[highlight setBackgroundBorder:border];
highlight.tapAction = ^(UIView *containerView, NSAttributedString *text, NSRange range, CGRect rect) {

};

//4.设置文本的高亮属性
[attributeStr yy_setTextHighlight:highlight range:NSMakeRange(0, 150)];

//5.赋值给YYLabel
YYLabel *yyLabel = [[YYLabel alloc] init];
yyLabel.attributedText = attributeStr;
yyLabel.numberOfLines = 0;
yyLabel.frame = CGRectMake(0.0, 0.0, self.view.bounds.size.width, 400.0);
[self.view addSubview:yyLabel];

3. 图文混排

YYText对我个人来说最大的用途除了高亮文本外就应该属图文混排了。YYText支持将UIView,CALayer,UIImage作为富文本添加到其他富文本中。用得比较多的是如下的接口:

/**
Creates and returns an attachment.
Example: ContentMode:bottom Alignment:Top.
The text The attachment holder
↓ ↓
─────────┌──────────────────────┐───────
/ \ │ │ / ___|
/ _ \ │ │| |
/ ___ \ │ │| |___ ←── The text line
/_/ \_\│ ██████████████ │ \____|
─────────│ ██████████████ │───────
│ ██████████████ │
│ ██████████████ ←───────────────── The attachment content
│ ██████████████ │
└──────────────────────┘

@param content The attachment (UIImage/UIView/CALayer).
@param contentMode The attachment's content mode in attachment holder
@param attachmentSize The attachment holder's size in text layout.
@param fontSize The attachment will align to this font.
@param alignment The attachment holder's alignment to text line.

@return An attributed string, or nil if an error occurs.
@since YYText:6.0
*/
+ (NSMutableAttributedString *)yy_attachmentStringWithContent:(nullable id)content
contentMode:(UIViewContentMode)contentMode
attachmentSize:(CGSize)attachmentSize
alignToFont:(UIFont *)font
alignment:(YYTextVerticalAlignment)alignment;

下面是一个简单例子:

NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:@"图片前面的文本"];
UIFont *font = [UIFont systemFontOfSize:18];
// 嵌入 UIImage
UIImage *image = [UIImage imageNamed:@"image"];
NSMutableAttributedString *attachment = nil;
attachment = [NSMutableAttributedString yy_attachmentStringWithContent:image contentMode:UIViewContentModeCenter attachmentSize:image.size alignToFont:font alignment:YYTextVerticalAlignmentCenter];
[text appendAttributedString: attachment];

NSMutableAttributedString *text1 = [[NSMutableAttributedString alloc] initWithString:@"图片后面的文本"];
[text appendAttributedString: text1];

YYLabel *yyLabel = [[YYLabel alloc] init];
yyLabel.attributedText = text;
yyLabel.numberOfLines = 0;
yyLabel.textColor = [UIColor blueColor];
yyLabel.font = [UIFont boldSystemFontOfSize:20.0];
yyLabel.frame = CGRectMake(0.0, 0.0, self.view.bounds.size.width, 400.0);
[self.view addSubview:yyLabel];

4. 文本容器


/**
The YYTextContainer class defines a region in which text is laid out.
YYTextLayout class uses one or more YYTextContainer objects to generate layouts.

A YYTextContainer defines rectangular regions (`size` and `insets`) or
nonrectangular shapes (`path`), and you can define exclusion paths inside the
text container's bounding rectangle so that text flows around the exclusion
path as it is laid out.

All methods in this class is thread-safe.

Example:

┌─────────────────────────────┐ <------- container
│ │
│ asdfasdfasdfasdfasdfa <------------ container insets
│ asdfasdfa asdfasdfa │
│ asdfas asdasd │
│ asdfa <----------------------- container exclusion path
│ asdfas adfasd │
│ asdfasdfa asdfasdfa │
│ asdfasdfasdfasdfasdfa │
│ │
└─────────────────────────────┘
*/

我们的布局都是基于文本容器的,YYTextContainer可以用size和inset指定规则的文本容器,可以使用path来指定不规则的文本容器,还可以通过exclusion在已有的容器中挖去一个形状。
我们用得比较多的是规则的矩形:

可以通过下面来获得对应的YYTextContainer:

/// Creates a container with the specified size and insets. @param size The size. @param insets The text insets.
+ (instancetype)containerWithSize:(CGSize)size insets:(UIEdgeInsets)insets;

/// Creates a container with the specified path. @param size The path.
+ (instancetype)containerWithPath:(nullable UIBezierPath *)path;

5. 文本布局计算

YYTextLayout是负责YYText的布局的类,它可以基于上面介绍的YYTextContainer还可以基于CGSize进行布局,除了少量绘制方法外大多数的属性是只读的线程安全的。

/**
YYTextLayout class is a readonly class stores text layout result.
All the property in this class is readonly, and should not be changed.
The methods in this class is thread-safe (except some of the draw methods).
example: (layout with a circle exclusion path)

┌──────────────────────────┐ <------ container
│ [--------Line0--------] │ <- Row0
│ [--------Line1--------] │ <- Row1
│ [-Line2-] [-Line3-] │ <- Row2
│ [-Line4] [Line5-] │ <- Row3
│ [-Line6-] [-Line7-] │ <- Row4
│ [--------Line8--------] │ <- Row5
│ [--------Line9--------] │ <- Row6
└──────────────────────────┘
*/

下面是最常用的两个布局方法:

/**
Generate a layout with the given container size and text.

@param size The text container's size
@param text The text (if nil, returns nil).
@return A new layout, or nil when an error occurs.
*/
+ (nullable YYTextLayout *)layoutWithContainerSize:(CGSize)size text:(NSAttributedString *)text;

/**
Generate a layout with the given container and text.

@param container The text container (if nil, returns nil).
@param text The text (if nil, returns nil).
@return A new layout, or nil when an error occurs.
*/
+ (nullable YYTextLayout *)layoutWithContainer:(YYTextContainer *)container text:(NSAttributedString *)text;

第一个基于规定尺寸的,第二个是基于文本容器的。

布局后用得比较多的属性如下:

///< Bounding rect (glyphs)
@property (nonatomic, readonly) CGRect textBoundingRect;
///< Bounding size (glyphs and insets, ceil to pixel)
@property (nonatomic, readonly) CGSize textBoundingSize;
///< Number of rows
@property (nonatomic, readonly) NSUInteger rowCount;

第一个是布局后文本的位置,第二个是文本的尺寸,最后一个是行数。下面是一个简单的用法:

CGSize size = CGSizeMake(300, CGFLOAT_MAX);
YYTextLayout *layout = [YYTextLayout layoutWithContainerSize:size text:text];
YYLabel *label = [[YYLabel alloc] init];
label.textColor = [UIColor blueColor];
label.frame = CGRectMake(0.0, 0.0, self.view.bounds.size.width, 400.0);
label.attributedText= text;
label.textLayout = layout;
[self.view addSubview:label];

6. 文本行位置调整

由于中文、英文、Emoji 高度不一致,或者富文本中出现了不同字号的字体;可能会造成每行文字的高度不一致。可以添加一个修改器来解决这个问题:


UILabel *label = [[UILabel alloc] init];
label.text = @"fsfdsfsdfsdffsfdsfsdfsdffsfdsfsdfsdffsfdsfsdfsdffsfdsfsdfsdffsfdsfsdfsdffsfdsfsdfsdffsfdsfsdfsdf我们women!!!☆★☆★☆★(=@__@=) O(∩_∩)O~我们women!!!我们women!!!我们women!!! (*^__^*)☆★☆★☆★我们women!!!我们women!!!我们women!!!我们women!!!我们women!!!";
label.numberOfLines = 0;
label.frame = CGRectMake(0.0, 0.0, self.view.bounds.size.width, 400.0);
label.textColor = [UIColor blueColor];
label.font = [UIFont boldSystemFontOfSize:20.0];
[self.view addSubview:label];

7. 异步排版和渲染

下面是官方给出的一个例子:

YYLabel *label = [YYLabel new];
label.displaysAsynchronously = YES;
label.ignoreCommonProperties = YES;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Create attributed string.
NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:@"Some Text"];
text.yy_font = [UIFont systemFontOfSize:16];
text.yy_color = [UIColor grayColor];
[text yy_setColor:[UIColor redColor] range:NSMakeRange(0, 4)];
// Create text container
YYTextContainer *container = [YYTextContainer new];
container.size = CGSizeMake(100, CGFLOAT_MAX);
container.maximumNumberOfRows = 0;
// Generate a text layout.
YYTextLayout *layout = [YYTextLayout layoutWithContainer:container text:text];
dispatch_async(dispatch_get_main_queue(), ^{
label.size = layout.textBoundingSize;
label.textLayout = layout;
});
});

8. 文本解析

YYTextParser用于text的解析,YYText默认内置了YYTextSimpleMarkdownParserYYTextSimpleEmoticonParser两种文本解析器。分别用于解析Markdown和Emoj表情。#pragma endregion
如果想要自定义文本解析器则只要遵循YYTextParser协议,并覆写如下方法:

/**
当文本改变的时候会调用这个方法
@param text 最初的富文本,这个方法会解析这个文本,并且修改它的内容
@param selectedRange 当前选择的文本内容
如果文本修改了就返回YES,如果没有修改则返回NO
*/
- (BOOL)parseText:(nullable NSMutableAttributedString *)text selectedRange:(nullable NSRangePointer)selectedRange;
// 内置简单的表情解析
YYTextSimpleEmoticonParser *parser = [YYTextSimpleEmoticonParser new];
NSMutableDictionary *mapper = [NSMutableDictionary new];
mapper[@":smile:"] = [UIImage imageNamed:@"smile.png"];
mapper[@":cool:"] = [UIImage imageNamed:@"cool.png"];
mapper[@":cry:"] = [UIImage imageNamed:@"cry.png"];
mapper[@":wink:"] = [UIImage imageNamed:@"wink.png"];
parser.emoticonMapper = mapper;

// 内置简单的 markdown 解析
YYTextSimpleMarkdownParser *parser = [YYTextSimpleMarkdownParser new];
[parser setColorWithDarkTheme];

// 实现 `YYTextParser` 协议的自定义解析器
MyCustomParser *parser = ...

// 2. 把解析器添加到 YYLabelYYTextView
YYLabel *label = ...
label.textParser = parser;

YYTextView *textView = ...
textView.textParser = parser;

9. YYTextBinding

YYTextBinding 用于将某些文本绑定在一起,在文本选择或者编辑的时候看作一个字符整体对待。

UIFont *font = [UIFont boldSystemFontOfSize:16];
for (int i = 0; i < tags.count; i++) {
NSString *tag = tags[i];
NSMutableAttributedString *tagText = [[NSMutableAttributedString alloc] initWithString:tag];
tagText.yy_font = font;
tagText.yy_color = [UIColor whiteColor];
[tagText yy_setTextBinding:[YYTextBinding bindingWithDeleteConfirm:NO] range:tagText.yy_rangeOfAll];

YYTextBorder *border = [YYTextBorder new];
border.strokeWidth = 1.5;
border.strokeColor = tagStrokeColors[i];
border.fillColor = tagFillColors[i];
border.cornerRadius = 100;
border.lineJoin = kCGLineJoinBevel;
border.insets = UIEdgeInsetsMake(-2, -5.5, -2, -8);

[tagText yy_setTextBackgroundBorder:border range:[tagText.string rangeOfString:tag]];
[text appendAttributedString:tagText];
}
text.yy_lineSpacing = 10;
text.yy_lineBreakMode = NSLineBreakByWordWrapping;
[text yy_appendString:@"\n"];
[text appendAttributedString:text];
_textView.attributedText = text;

10. YYTextShadow

YYTextShadow 是给富文本添加阴影用的:

添加外阴影:

NSMutableAttributedString *one = [[NSMutableAttributedString alloc] initWithString:@"Shadow"];
one.yy_font = [UIFont boldSystemFontOfSize:30];
one.yy_color = [UIColor whiteColor];
YYTextShadow *shadow = [YYTextShadow new];
shadow.color = [UIColor colorWithWhite:0.000 alpha:0.490];
shadow.offset = CGSizeMake(0, 1);
shadow.radius = 5;
one.yy_textShadow = shadow;

添加内阴影:

NSMutableAttributedString *one = [[NSMutableAttributedString alloc] initWithString:@"Inner Shadow"];
one.yy_font = [UIFont boldSystemFontOfSize:30];
one.yy_color = [UIColor whiteColor];
YYTextShadow *shadow = [YYTextShadow new];
shadow.color = [UIColor colorWithWhite:0.000 alpha:0.40];
shadow.offset = CGSizeMake(0, 1);
shadow.radius = 1;
one.yy_textInnerShadow = shadow;

添加子阴影:

NSMutableAttributedString *one = [[NSMutableAttributedString alloc] initWithString:@"Multiple Shadows"];
one.yy_font = [UIFont boldSystemFontOfSize:30];
one.yy_color = [UIColor colorWithRed:1.000 green:0.795 blue:0.014 alpha:1.000];

YYTextShadow *shadow = [YYTextShadow new];
shadow.color = [UIColor colorWithWhite:0.000 alpha:0.20];
shadow.offset = CGSizeMake(0, -1);
shadow.radius = 1.5;
YYTextShadow *subShadow = [YYTextShadow new];
subShadow.color = [UIColor colorWithWhite:1 alpha:0.99];
subShadow.offset = CGSizeMake(0, 1);
subShadow.radius = 1.5;
shadow.subShadow = subShadow;
one.yy_textShadow = shadow;

给高亮文本添加内外阴影:

NSMutableAttributedString *one = [[NSMutableAttributedString alloc] initWithString:@"Yet Another Link"];
one.yy_font = [UIFont boldSystemFontOfSize:30];
one.yy_color = [UIColor whiteColor];

YYTextShadow *shadow = [YYTextShadow new];
shadow.color = [UIColor colorWithWhite:0.000 alpha:0.490];
shadow.offset = CGSizeMake(0, 1);
shadow.radius = 5;
one.yy_textShadow = shadow;

YYTextShadow *shadow0 = [YYTextShadow new];
shadow0.color = [UIColor colorWithWhite:0.000 alpha:0.20];
shadow0.offset = CGSizeMake(0, -1);
shadow0.radius = 1.5;
YYTextShadow *shadow1 = [YYTextShadow new];
shadow1.color = [UIColor colorWithWhite:1 alpha:0.99];
shadow1.offset = CGSizeMake(0, 1);
shadow1.radius = 1.5;
shadow0.subShadow = shadow1;

YYTextShadow *innerShadow0 = [YYTextShadow new];
innerShadow0.color = [UIColor colorWithRed:0.851 green:0.311 blue:0.000 alpha:0.780];
innerShadow0.offset = CGSizeMake(0, 1);
innerShadow0.radius = 1;

YYTextHighlight *highlight = [YYTextHighlight new];
[highlight setColor:[UIColor colorWithRed:1.000 green:0.795 blue:0.014 alpha:1.000]];
[highlight setShadow:shadow0];
[highlight setInnerShadow:innerShadow0];
[one yy_setTextHighlight:highlight range:one.yy_rangeOfAll];

11. YYTextBorder

YYTextBorder用于为文本添加边框或者背景

YYTextBorder *border = [YYTextBorder new];
border.strokeColor = [UIColor colorWithRed:1.000 green:0.029 blue:0.651 alpha:1.000];
border.strokeWidth = 3;
border.lineStyle = YYTextLineStylePatternCircleDot;
border.cornerRadius = 3;
border.insets = UIEdgeInsetsMake(0, -4, 0, -4);
one.yy_textBackgroundBorder = border;

作为高亮文本的填充:

YYTextBorder *border = [YYTextBorder new];
border.cornerRadius = 50;
border.insets = UIEdgeInsetsMake(0, -10, 0, -10);
border.strokeWidth = 0.5;
border.strokeColor = one.yy_color;
border.lineStyle = YYTextLineStyleSingle;
one.yy_textBackgroundBorder = border;

YYTextBorder *highlightBorder = border.copy;
highlightBorder.strokeWidth = 0;
highlightBorder.strokeColor = one.yy_color;
highlightBorder.fillColor = one.yy_color;

YYTextHighlight *highlight = [YYTextHighlight new];
[highlight setColor:[UIColor whiteColor]];
[highlight setBackgroundBorder:highlightBorder];
highlight.tapAction = ^(UIView *containerView, NSAttributedString *text, NSRange range, CGRect rect) {
[_self showMessage:[NSString stringWithFormat:@"Tap: %@",[text.string substringWithRange:range]]];
};
[one yy_setTextHighlight:highlight range:one.yy_rangeOfAll];

12. Debug

YYTextDebugOption *debugOptions = [YYTextDebugOption new];
[YYTextDebugOption setSharedDebugOption:debugOptions];

下面是YYTextDebugOption的配置

@property (nullable, nonatomic, strong) UIColor *baselineColor;      ///< baseline color
@property (nullable, nonatomic, strong) UIColor *CTFrameBorderColor; ///< CTFrame path border color
@property (nullable, nonatomic, strong) UIColor *CTFrameFillColor; ///< CTFrame path fill color
@property (nullable, nonatomic, strong) UIColor *CTLineBorderColor; ///< CTLine bounds border color
@property (nullable, nonatomic, strong) UIColor *CTLineFillColor; ///< CTLine bounds fill color
@property (nullable, nonatomic, strong) UIColor *CTLineNumberColor; ///< CTLine line number color
@property (nullable, nonatomic, strong) UIColor *CTRunBorderColor; ///< CTRun bounds border color
@property (nullable, nonatomic, strong) UIColor *CTRunFillColor; ///< CTRun bounds fill color
@property (nullable, nonatomic, strong) UIColor *CTRunNumberColor; ///< CTRun number color
@property (nullable, nonatomic, strong) UIColor *CGGlyphBorderColor; ///< CGGlyph bounds border color
@property (nullable, nonatomic, strong) UIColor *CGGlyphFillColor; ///< CGGlyph bounds fill color

13. 其他

用YYTextWeakProxy避免被NSTimer或者CADisplayLink持有导致循环引用:

@implementation MyView {
NSTimer *_timer;
}

- (void)initTimer {
YYTextWeakProxy *proxy = [YYTextWeakProxy proxyWithTarget:self];
_timer = [NSTimer timerWithTimeInterval:0.1 target:proxy selector:@selector(tick:) userInfo:nil repeats:YES];
}

- (void)tick:(NSTimer *)timer {...}
@end
Contents
  1. 1. 开源代码信息
  2. 2. YYText的使用