YYText使用篇(一)

版本记录

版本号 时间
V1.0 2017.06.04

前言

YYText是一个专门处理文字的框架,作者是国内的一个技术大牛,他有很多框架,还有我们知道的YYModel、YYText、YYCache等,这里我们就先说一下YYText。

一、YYText作者

我们先看一下YYText的作者,以及他的其他框架。

YYText

二、YYText框架特点

YYText具有如下特点:

  • 兼容UILabel和UITextView API框架
  • 高性能异步文字布局和渲染
  • CoreText可扩展,拥有更多的文字效果
  • 具有UIImage,UIView和CALayer富文本效果
  • 自定义高亮文字允许用户交互
  • 文本解析器(内置markdown/表情解析器)
  • 支持文本容器路径和排除路径
  • 支持垂直表单布局(对于CJK文本)
  • 支持图像和特性文字的粘贴和赋值
  • 支持特性文字占位符
  • 支持自定义键盘视图
  • 撤销和重新控制
  • 支持特性文字的归档和解档
  • 支持多语言和VoiceOver
  • 支持Interface Builder
  • 技术文档齐备

三、YYText vs TextKit结构

下面我们看一下这两种框架的结构。

YYText vs TextKit结构

四、YYText支持的文本特性

1.YYText原生支持的特性

示例1

示例1

示例2

示例2

示例3

示例3

示例4

示例4

示例5

示例5

示例6

示例6

示例7

示例7

示例8

示例8-1
示例8-2
示例8-3

2.YYText 支持的 CoreText 属性

<tr>
  <td>![](https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/Alignment.png)</td>
  <td> TextAlignment </td>
  <td> NSParagraphStyle <br/>(NSTextAlignment) </td>
</tr>
<tr>
  <td>![](https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/LineBreakMode.png)</td>
  <td> LineBreakMode </td>
  <td> NSParagraphStyle <br/>(NSLineBreakMode) </td>
</tr>
<tr>
  <td>![](https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/LineSpacing.png)</td>
  <td> LineSpacing </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td>![](https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/ParagraphSpacing.png)</td>
  <td> ParagraphSpacing <br/> ParagraphSpacingBefore </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td>![](https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/FirstLineHeadIndent.png)</td>
  <td> FirstLineHeadIndent </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td>![](https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/HeadIndent.png)</td>
  <td> HeadIndent </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td>![](https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/TailIndent.png)</td>
  <td> TailIndent </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td>![](https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/MinimumLineHeight.png)</td>
  <td> MinimumLineHeight </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td>![](https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/MaximumLineHeight.png)</td>
  <td> MaximumLineHeight </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td>![](https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/LineHeightMultiple.png)</td>
  <td> LineHeightMultiple </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td>![](https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/BaseWritingDirection.png)</td>
  <td> BaseWritingDirection </td>
  <td> NSParagraphStyle <br/>(NSWritingDirection) </td>
</tr>
<tr>
  <td>![](https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/Tab.png)</td>
  <td> DefaultTabInterval <br/> TabStops </td>
  <td> NSParagraphStyle <br/>CGFloat/NSArray(NSTextTab)</td>
</tr>

下面是效果图

示例图
示例图
示例图

五、YYText用法

1. 基本用法

// 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 = ...

2. 属性文本

// 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;

3. 文本高亮

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

[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:...");
}

4. 图文混排

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];

5. 文本布局计算

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;

6. 文本行位置调整

// 由于中文、英文、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;

7. 异步排版和渲染

// 如果你在显示字符串时有性能问题,可以这样开启异步模式:
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;
    });
});

8. 文本容器控制

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;

9. 文本解析

// 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;

10. Debug

// 设置一个全局的 debug option 来显示排版结果。
YYTextDebugOption *debugOptions = [YYTextDebugOption new];
debugOptions.baselineColor = [UIColor redColor];
debugOptions.CTFrameBorderColor = [UIColor redColor];
debugOptions.CTLineFillColor = [UIColor colorWithRed:0.000 green:0.463 blue:1.000 alpha:0.180];
debugOptions.CGGlyphBorderColor = [UIColor colorWithRed:1.000 green:0.524 blue:0.000 alpha:0.200];
[YYTextDebugOption setSharedDebugOption:debugOptions];


六、YYText安装

1. CocoaPods

1. 在 Podfile 中添加 pod 'YYText'。
2. 执行 pod install 或 pod update。
3. 导入 <YYText/YYText.h>。

2. Carthage

1. 在 Cartfile 中添加 github "ibireme/YYText"。
2. 执行 carthage update --platform ios 并将生成的 framework 添加到你的工程。
3. 导入 <YYText/YYText.h>。

3. 手动安装

1. 下载 YYText 文件夹内的所有内容。
2. 将 YYText 内的源文件添加(拖放)到你的工程。
3. 链接以下 frameworks:
      - UIKit
      - CoreFoundation
      - CoreText
      - QuartzCore
      - Accelerate
      - MobileCoreServices
4. 导入 YYText.h。

注意

你可以添加 YYImage 或 YYWebImage 到你的工程,以支持动画格式(GIF/APNG/WebP)的图片。


七、系统要求

该项目最低支持 iOS 6.0 和 Xcode 7.0。


八、已知问题

  • YYText 并不能支持所有 CoreText/TextKit 的属性,比如 NSBackgroundColor、NSStrikethrough、NSUnderline、NSAttachment、NSLink 等,但 YYText 中基本都有对应属性作为替代。详情见上方表格。
  • YYTextView 未实现局部刷新,所以在输入和编辑大量的文本(比如超过大概五千个汉字、或大概一万个英文字符)时会出现较明显的卡顿现象。
  • 竖排版时,添加 exclusionPaths 在少数情况下可能会导致文本显示空白。
  • 当添加了非矩形的 textContainerPath,并且有嵌入大于文本排版方向宽度的 RunDelegate 时,RunDelegate 之后的文字会无法显示。这是 CoreText 的 Bug(或者说是 Feature)。

后记

未完,待续,后续会完善~~~~

奋斗
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容

  • 卷首语 欢迎来到 objc.io 第五期! 我们希望你跟我们一样为 iOS 7 的发布而感到兴奋。选择这个做为本期...
    评评分分阅读 556评论 0 4
  • iOS中的文字渲染 在iOS出现早期,显示特性文本唯一可行的办法就是使用UIWebView和利用HTML来处理定制...
    正谦阅读 653评论 0 1
  • 本文主要帮助刚入门学习Go语言的小伙伴,系统地了解Go的基础知识,倾向于有一定其他语言编程经验的小伙伴,本文为目录...
    雨生_阅读 438评论 0 0
  • 何谓“情商” 情商可塑吗?众心理学家各执一词。之所以未能达成共识,部分原因在于概念本身的含混不清。1995年,《纽...
    小梳子0725阅读 784评论 3 3
  • 相隔愈远,思念愈深;历时愈久,思念愈切;长夜漫漫,相思之情何时了? 就这样分手了。 1 第一阶段,当然是丧尽自尊,...
    醒醒老师阅读 513评论 0 0