YYText

特性

  • API 兼容 UILabel 和 UITextView
  • 支持高性能的异步排版和渲染
  • 扩展了 CoreText 的属性以支持更多文字效果
  • 支持 UIImage、UIView、CALayer 作为图文混排元素
  • 支持添加自定义样式的、可点击的文本高亮范围
  • 支持自定义文本解析 (内置简单的 Markdown/表情解析)
  • 支持文本容器路径、内部留空路径的控制
  • 支持文字竖排版,可用于编辑和显示中日韩文本
  • 支持图片和富文本的复制粘贴
  • 文本编辑时,支持富文本占位符
  • 支持自定义键盘视图
  • 撤销和重做次数的控制
  • 富文本的序列化与反序列化支持
  • 支持多语言,支持 VoiceOver
  • 支持 Interface Builder
  • 全部代码都有文档注释

架构

YYText 和 TextKit 架构对比

YYText_第1张图片

文本属性

YYText 原生支持的属性

Demo Attribute Name Class
TextAttachment YYTextAttachment
YYText_第2张图片 TextHighlight YYTextHighlight
YYText_第3张图片 TextBinding YYTextBinding
YYText_第4张图片 TextShadow
TextInnerShadow
YYTextShadow
YYText_第5张图片 TextBorder YYTextBorder
YYText_第6张图片 TextBackgroundBorder YYTextBorder
YYText_第7张图片 TextBlockBorder YYTextBorder
YYText_第8张图片 TextGlyphTransform NSValue(CGAffineTransform)
YYText_第9张图片 TextUnderline YYTextDecoration
YYText_第10张图片 TextStrickthrough YYTextDecoration
YYText_第11张图片 TextBackedString YYTextBackedString

YYText 支持的 CoreText 属性

Demo Attribute Name Class
YYText_第12张图片 Font  UIFont(CTFontRef)
YYText_第13张图片 Kern  NSNumber
YYText_第14张图片 StrokeWidth  NSNumber 
YYText_第15张图片 StrokeColor  CGColorRef 
YYText_第16张图片 Shadow  NSShadow 
YYText_第17张图片 Ligature  NSNumber 
YYText_第18张图片 VerticalGlyphForm  NSNumber(BOOL) 
YYText_第19张图片 WritingDirection  NSArray(NSNumber) 
YYText_第20张图片 RunDelegate  CTRunDelegateRef 
YYText_第21张图片 TextAlignment  NSParagraphStyle 
(NSTextAlignment) 
YYText_第22张图片 LineBreakMode  NSParagraphStyle 
(NSLineBreakMode) 
YYText_第23张图片 LineSpacing  NSParagraphStyle 
(CGFloat) 
YYText_第24张图片 ParagraphSpacing 
ParagraphSpacingBefore 
NSParagraphStyle 
(CGFloat) 
YYText_第25张图片 FirstLineHeadIndent  NSParagraphStyle 
(CGFloat) 
YYText_第26张图片 HeadIndent  NSParagraphStyle 
(CGFloat) 
YYText_第27张图片 TailIndent  NSParagraphStyle 
(CGFloat) 
YYText_第28张图片 MinimumLineHeight  NSParagraphStyle 
(CGFloat) 
YYText_第29张图片 MaximumLineHeight  NSParagraphStyle 
(CGFloat) 
YYText_第30张图片 LineHeightMultiple  NSParagraphStyle 
(CGFloat) 
YYText_第31张图片 BaseWritingDirection  NSParagraphStyle 
(NSWritingDirection) 
YYText_第32张图片 DefaultTabInterval 
TabStops 
NSParagraphStyle 
CGFloat/NSArray(NSTextTab)

用法

基本用法

// YYLabel (和 UILabel 用法一致)
YYLabel *label = [YYLabel new];
label.frame = ...
label.font = ...
label.textColor = ...
label.textAlignment = ...
label.lineBreakMode = ...
label.numberOfLines = ...
label.text = ...

// YYTextView (和 UITextView 用法一致)
YYTextView *textView = [YYTextView new];
textView.frame = ...
textView.font = ...
textView.textColor = ...
textView.dataDetectorTypes = ...
textView.placeHolderText = ...
textView.placeHolderTextColor = ...
textView.delegate = ...

属性文本

// 1. 创建一个属性文本
NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:@"Some Text, blabla..."];

// 2. 为文本设置属性
text.yy_font = [UIFont boldSystemFontOfSize:30];
text.yy_color = [UIColor blueColor];
[text yy_setColor:[UIColor redColor] range:NSmakeRange(0, 4)];
text.yy_lineSpacing = 10;

// 3. 赋值到 YYLabel 或 YYTextView
YYLabel *label = [YYLabel new];
label.frame = ...
label.attributedString = text;

YYTextView *textView = [YYTextView new];
textView.frame = ...
textView.attributedString = text;

文本高亮

你可以用一些已经封装好的简便方法来设置文本高亮:

[text yy_setTextHighlightRange:range
                        color:[UIColor blueColor]
              backgroundColor:[UIColor grayColor]
                    tapAction:^(UIView *containerView, NSAttributedString *text, NSRange range, CGRect rect){ 
                        NSLog(@"tap text range:..."); 
                    }];

或者用更复杂的办法来调节文本高亮的细节:

// 1. 创建一个"高亮"属性,当用户点击了高亮区域的文本时,"高亮"属性会替换掉原本的属性
YYTextBorder *border = [YYTextBorder borderWithFillColor:[UIColor grayColor] cornerRadius:3];

YYTextHighlight *highlight = [YYTextHighlight new];
[highlight setColor:[UIColor whiteColor]];
[highlight setBackgroundBorder:highlightBorder];
highlight.tapAction = ^(UIView *containerView, NSAttributedString *text, NSRange range, CGRect rect) {
  NSLog(@"tap text range:..."); 
  // 你也可以把事件回调放到 YYLabel 和 YYTextView 来处理。
};

// 2. 把"高亮"属性设置到某个文本范围
[attributedText yy_setTextHighlight:highlight range:highlightRange];

// 3. 把属性文本设置到 YYLabel 或 YYTextView
YYLabel *label = ...
label.attributedText = attributedText

YYTextView *textView = ...
textView.attributedText = ...

// 4. 接受事件回调
label.highlightTapAction = ^(UIView *containerView, NSAttributedString *text, NSRange range, CGRect rect) {
    NSLog(@"tap text range:...");
};
label.highlightLongPressAction = ^(UIView *containerView, NSAttributedString *text, NSRange range, CGRect rect) {
    NSLog(@"long press text range:...");
};

@UITextViewDelegate
- (void)textView:(YYTextView *)textView didTapHighlight:(YYTextHighlight *)highlight inRange:(NSRange)characterRange rect:(CGRect)rect {
    NSLog(@"tap text range:...");
}
- (void)textView:(YYTextView *)textView didLongPressHighlight:(YYTextHighlight *)highlight inRange:(NSRange)characterRange rect:(CGRect)rect {
    NSLog(@"long press text range:...");
}

图文混排

NSMutableAttributedString *text = [NSMutableAttributedString new];
UIFont *font = [UIFont systemFontOfSize:16];
NSMutableAttributedString *attachment = nil;

// 嵌入 UIImage
UIImage *image = [UIImage imageNamed:@"dribbble64_imageio"];
attachment = [NSMutableAttributedString yy_attachmentStringWithContent:image contentMode:UIViewContentModeCenter attachmentSize:image.size alignToFont:font alignment:YYTextVerticalAlignmentCenter];
[text appendAttributedString: attachment];

// 嵌入 UIView
UISwitch *switcher = [UISwitch new];
[switcher sizeToFit];
attachment = [NSMutableAttributedString yy_attachmentStringWithContent:switcher contentMode:UIViewContentModeBottom attachmentSize:switcher.size alignToFont:font alignment:YYTextVerticalAlignmentCenter];
[text appendAttributedString: attachment];

// 嵌入 CALayer
CASharpLayer *layer = [CASharpLayer layer];
layer.path = ...
attachment = [NSMutableAttributedString yy_attachmentStringWithContent:layer contentMode:UIViewContentModeBottom attachmentSize:switcher.size alignToFont:font alignment:YYTextVerticalAlignmentCenter];
[text appendAttributedString: attachment];

文本布局计算

NSAttributedString *text = ...
CGSize size = CGSizeMake(100, CGFLOAT_MAX);
YYTextLayout *layout = [YYTextLayout layoutWithContainerSize:size text:text];

// 获取文本显示位置和大小
layout.textBoundingRect; // get bounding rect
layout.textBoundingSize; // get bounding size

 // 查询文本排版结果
[layout lineIndexForPoint:CGPointMake(10,10)];
[layout closestLineIndexForPoint:CGPointMake(10,10)];
[layout closestPositionToPoint:CGPointMake(10,10)];
[layout textRangeAtPoint:CGPointMake(10,10)];
[layout rectForRange:[YYTextRange rangeWithRange:NSMakeRange(10,2)]];
[layout selectionRectsForRange:[YYTextRange rangeWithRange:NSMakeRange(10,2)]];

// 显示文本排版结果
YYLabel *label = [YYLabel new];
label.size = layout.textBoundingSize;
label.textLayout = layout;

文本行位置调整

// 由于中文、英文、Emoji 等字体高度不一致,或者富文本中出现了不同字号的字体,
// 可能会造成每行文字的高度不一致。这里可以添加一个修改器来实现固定行高,或者自定义文本行位置。

// 简单的方法:
// 1. 创建一个文本行位置修改类,实现 `YYTextLinePositionModifier` 协议。
// 2. 设置到 Label 或 TextView。

YYTextLinePositionSimpleModifier *modifier = [YYTextLinePositionSimpleModifier new];
modifier.fixedLineHeight = 24;

YYLabel *label = [YYLabel new];
label.linePositionModifier = modifier;

// 完全控制:
YYTextLinePositionSimpleModifier *modifier = [YYTextLinePositionSimpleModifier new];
modifier.fixedLineHeight = 24;

YYTextContainer *container = [YYTextContainer new];
container.size = CGSizeMake(100, CGFLOAT_MAX);
container.linePositionModifier = modifier;

YYTextLayout *layout = [YYTextLayout layoutWithContainer:container text:text];
YYLabel *label = [YYLabel new];
label.size = layout.textBoundingSize;
label.textLayout = layout;

异步排版和渲染

// 如果你在显示字符串时有性能问题,可以这样开启异步模式:
YYLabel *label = ...
label.displaysAsynchronously = YES;

// 如果需要获得最高的性能,你可以在后台线程用 `YYTextLayout` 进行预排版: 
YYLabel *label = [YYLabel new];
label.displaysAsynchronously = YES; //开启异步绘制
label.ignoreCommonProperties = YES; //忽略除了 textLayout 之外的其他属性

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 创建属性字符串
    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)];

    // 创建文本容器
    YYTextContainer *container = [YYTextContainer new];
    container.size = CGSizeMake(100, CGFLOAT_MAX);
    container.maximumNumberOfRows = 0;

    // 生成排版结果
    YYTextLayout *layout = [YYTextLayout layoutWithContainer:container text:text];

    dispatch_async(dispatch_get_main_queue(), ^{
        label.size = layout.textBoundingSize;
        label.textLayout = layout;
    });
});

文本容器控制

YYLabel *label = ...
label.textContainerPath = [UIBezierPath bezierPathWith...];
label.exclusionPaths =  @[[UIBezierPath bezierPathWith...];,...];
label.textContainerInset = UIEdgeInsetsMake(...);
label.verticalForm = YES/NO;

YYTextView *textView = ...
textView.exclusionPaths =   @[[UIBezierPath bezierPathWith...];,...];
textView.textContainerInset = UIEdgeInsetsMake(...);
textView.verticalForm = YES/NO;

文本解析

// 1. 创建一个解析器

// 内置简单的表情解析
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. 把解析器添加到 YYLabel 或 YYTextView
YYLabel *label = ...
label.textParser = parser;

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

更多示

你可能感兴趣的:(YYText)