注册

iOS 超强富文本编辑库

YYText

功能强大的 iOS 富文本编辑与显示框架

特性

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

架构

YYText 和 TextKit 架构对比

68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f6172636869746563747572652e706e67



文本属性

YYText 原生支持的属性

DemoAttribute NameClass
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f59595465787420457874656e6465642f5959546578744174746163686d656e742e676966TextAttachmentYYTextAttachment
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f59595465787420457874656e6465642f595954657874486967686c696768742e676966TextHighlightYYTextHighlight
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f59595465787420457874656e6465642f59595465787442696e64696e672e676966TextBindingYYTextBinding
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f59595465787420457874656e6465642f595954657874536861646f772e706e67TextShadow
TextInnerShadow
YYTextShadow
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f59595465787420457874656e6465642f595954657874426f726465722e706e67TextBorderYYTextBorder
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f59595465787420457874656e6465642f5959546578744261636b67726f756e64426f726465722e706e67TextBackgroundBorderYYTextBorder
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f59595465787420457874656e6465642f595954657874426c6f636b426f726465722e706e67TextBlockBorderYYTextBorder
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f4f626c697175656e6573732e706e67TextGlyphTransformNSValue(CGAffineTransform)
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f556e6465726c696e652e706e67TextUnderlineYYTextDecoration
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f537472696b657468726f7567682e706e67TextStrickthroughYYTextDecoration
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f59595465787420457874656e6465642f5959546578744261636b6564537472696e672e706e67TextBackedStringYYTextBackedString

YYText 支持的 CoreText 属性

DemoAttribute NameClass
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f466f6e742e706e67Font UIFont(CTFontRef)
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f4b65726e2e706e67Kern NSNumber
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f5374726f6b652e706e67StrokeWidth NSNumber 
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f5374726f6b65436f6c6f722e706e67StrokeColor CGColorRef 
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f536861646f772e706e67Shadow NSShadow 
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f4c696761747572652e706e67Ligature NSNumber 
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f566572746963616c466f726d732e706e67VerticalGlyphForm NSNumber(BOOL) 
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f5772697465446972656374696f6e2e706e67WritingDirection NSArray(NSNumber) 
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f52756e44656c65676174652e706e67RunDelegate CTRunDelegateRef 
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f5061726167726170682f416c69676e6d656e742e706e67TextAlignment NSParagraphStyle 
(NSTextAlignment) 
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f5061726167726170682f4c696e65427265616b4d6f64652e706e67LineBreakMode NSParagraphStyle 
(NSLineBreakMode) 
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f5061726167726170682f4c696e6553706163696e672e706e67LineSpacing NSParagraphStyle 
(CGFloat) 
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f5061726167726170682f50617261677261706853706163696e672e706e67ParagraphSpacing 
ParagraphSpacingBefore 
NSParagraphStyle 
(CGFloat) 
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f5061726167726170682f46697273744c696e6548656164496e64656e742e706e67FirstLineHeadIndent NSParagraphStyle 
(CGFloat) 
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f5061726167726170682f48656164496e64656e742e706e67HeadIndent NSParagraphStyle 
(CGFloat) 
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f5061726167726170682f5461696c496e64656e742e706e67TailIndent NSParagraphStyle 
(CGFloat) 
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f5061726167726170682f4d696e696d756d4c696e654865696768742e706e67MinimumLineHeight NSParagraphStyle 
(CGFloat) 
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f5061726167726170682f4d6178696d756d4c696e654865696768742e706e67MaximumLineHeight NSParagraphStyle 
(CGFloat) 
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f5061726167726170682f4c696e654865696768744d756c7469706c652e706e67LineHeightMultiple NSParagraphStyle 
(CGFloat) 
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f5061726167726170682f4261736557726974696e67446972656374696f6e2e706e67BaseWritingDirection NSParagraphStyle 
(NSWritingDirection) 
68747470733a2f2f7261772e6769746875622e636f6d2f69626972656d652f5959546578742f6d61737465722f417474726962757465732f436f72655465787420616e6420546578744b69742f5061726167726170682f5461622e706e67DefaultTabInterval 
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:...");
}];

文本高亮

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

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

部分效果展示

4d9c4145550c72de2d0d5621e3930d0a.gif


389f86ca2a5de6ec5afe037debb6aec6.gif



安装

CocoaPods

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

Carthage

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

手动安装

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


已知问题

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


常见问题及源码下载:点击这里

demo:YYText.zip


1 个评论

已下载

要回复文章请先登录注册