LRYYText 1.0.7.5

LRYYText 1.0.7.5

1989925kdash维护。



LRYYText 1.0.7.5

YYText

许可证 MIT  Carthage 兼容  [CocoaPods](https://cocoapods.org.cn/?q= YYText)  [CocoaPods](https://cocoapods.org.cn/?q= YYText)  支持  构建状态

一款强大的iOS富文本显示和编辑框架。
(它是YYKit的组件)

特点

  • 与UILabel和UITextView API兼容
  • 高性能的异步文本布局和渲染
  • 扩展了CoreText属性,增加了更多文本效果
  • 支持文本附件,包括UIImage,UIView和CALayer
  • 自定义高亮文本范围,允许用户与之交互
  • 支持文本解析器(内置markdown/表情符号解析器)
  • 支持文本容器路径和排除路径
  • 垂直表布局支持(适用于CJK文本)
  • 图像和属性文本复制/粘贴支持
  • 属性文本占位符支持
  • 自定义键盘视图支持
  • 撤销和重做控制
  • 属性文本存档和恢复支持
  • 多语言和VoiceOver支持
  • 界面构建器支持
  • 全面文档化

架构

YYText vs TextKit

文本属性

YYText支持的属性

演示 属性名
TextAttachment YYTextAttachment
TextHighlight YYTextHighlight
TextBinding YYTextBinding
TextShadow
TextInnerShadow
YYTextShadow
TextBorder YYTextBorder
TextBackgroundBorder YYTextBorder
TextBlockBorder YYTextBorder
TextGlyphTransform NSValue(CGAffineTransform)
TextUnderline YYTextDecoration
TextStrickthrough YYTextDecoration
TextBackedString YYTextBackedString

###YYText支持的CoreText属性

<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/Alignment.png" width="200"></td>
  <td> TextAlignment </td>
  <td> NSParagraphStyle <br/>(NSTextAlignment) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/LineBreakMode.png" width="200"></td>
  <td> LineBreakMode </td>
  <td> NSParagraphStyle <br/>(NSLineBreakMode) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/LineSpacing.png" width="200"></td>
  <td> LineSpacing </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/ParagraphSpacing.png" width="200"></td>
  <td> ParagraphSpacing <br/> ParagraphSpacingBefore </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/FirstLineHeadIndent.png" width="200"></td>
  <td> FirstLineHeadIndent </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/HeadIndent.png" width="200"></td>
  <td> HeadIndent </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/TailIndent.png" width="200"></td>
  <td> TailIndent </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/MinimumLineHeight.png" width="200"></td>
  <td> MinimumLineHeight </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/MaximumLineHeight.png" width="200"></td>
  <td> MaximumLineHeight </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/LineHeightMultiple.png" width="200"></td>
  <td> LineHeightMultiple </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/BaseWritingDirection.png" width="200"></td>
  <td> BaseWritingDirection </td>
  <td> NSParagraphStyle <br/>(NSWritingDirection) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/Tab.png" width="200"></td>
  <td> DefaultTabInterval <br/> TabStops </td>
  <td> NSParagraphStyle <br/>CGFloat/NSArray(NSTextTab)</td>
</tr>
演示 属性名
字体 UIFont(CTFontRef)
字距 NSNumber
描边宽度 NSNumber
描边颜色 CGColorRef
阴影 NSShadow
连字 NSNumber
垂直字形 NSNumber(BOOL)
书写方向 NSArray(NSNumber)
RunDelegate CTRunDelegateRef

使用方法

基本用法

// YYLabel (similar to UILabel)
YYLabel *label = [YYLabel new];
label.frame = ...
label.font = ...
label.textColor = ...
label.textAlignment = ...
label.lineBreakMode = ...
label.numberOfLines = ...
label.text = ...

// YYTextView (similar to UITextView)
YYTextView *textView = [YYTextView new];
textView.frame = ...
textView.font = ...
textView.textColor = ...
textView.dataDetectorTypes = ...
textView.placeHolderText = ...
textView.placeHolderTextColor = ...
textView.delegate = ...

归属文本

// 1. Create an attributed string.
NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:@"Some Text, blabla..."];

// 2. Set attributes to text, you can use almost all CoreText attributes.
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. Set to YYLabel or 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. Create a 'highlight' attribute for text.
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:..."); 
  // you can also set the action handler to YYLabel or YYTextView.
};

// 2. Add 'highlight' attribute to a range of text.
[attributedText yy_setTextHighlight:highlight range:highlightRange];

// 3. Set text to label or text view.
YYLabel *label = ...
label.attributedText = attributedText

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

// 4. Receive user interactive action.
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 attachment
UIImage *image = [UIImage imageNamed:@"dribbble64_imageio"];
attachment = [NSMutableAttributedString yy_attachmentStringWithContent:image contentMode:UIViewContentModeCenter attachmentSize:image.size alignToFont:font alignment:YYTextVerticalAlignmentCenter];
[text appendAttributedString: attachment];

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

// CALayer attachment
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];

// get text bounding
layout.textBoundingRect; // get bounding rect
layout.textBoundingSize; // get bounding size

 // query text layout
[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)]];

// text layout display
YYLabel *label = [YYLabel new];
label.size = layout.textBoundingSize;
label.textLayout = layout;

调整文本行位置

// Convenience methods:
// 1. Create a text line position modifier, implements `YYTextLinePositionModifier` protocol.
// 2. Set it to label or text view.

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

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

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

异步布局和渲染

// If you have performance issues,
// you may enable the asynchronous display mode.
YYLabel *label = ...
label.displaysAsynchronously = YES;

// If you want to get the highest performance, you should do 
// text layout with `YYTextLayout` class in background thread.
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;
    });
});

文本容器控制

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. Create a text parser

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;

YYTextSimpleMarkdownParser *parser = [YYTextSimpleMarkdownParser new];
[parser setColorWithDarkTheme];

MyCustomParser *parser = ... // custom parser

// 2. Attach parser to label or text view
YYLabel *label = ...
label.textParser = parser;

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

调试

// Set a shared debug option to show text layout result.
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];

更多示例

查看 Demo/YYTextDemo.xcodeproj 获取更多示例



安装

CocoaPods

  1. pod 'YYText' 添加到您的 Podfile。
  2. 运行 pod installpod update
  3. 导入 <YYText/YYText.h>。

Carthage

  1. github "ibireme/YYText" 添加到您的 Cartfile。
  2. 运行 carthage update --platform ios 并将框架添加到项目中。
  3. 导入 <YYText/YYText.h>。

手动安装

  1. 下载 YYText 子目录下的所有文件。
  2. 将源文件添加到您的 Xcode 项目中。
  3. 链接所需的框架
    • UIKit
    • CoreFoundation
    • CoreText
    • QuartzCore
    • Accelerate
    • MobileCoreServices
  4. 导入 YYText.h

注意

如果您想支持动态图片(GIF/APNG/WebP),可以将其中的 YYImageYYWebImage 添加到您的项目中。

文档

完整的API文档可以在 CocoaDocs 上找到。
您也可以用 appledoc 在本地安装文档。

需求

此库需要 iOS 6.0+Xcode 7.0+

许可证

YYText以MIT许可证发布。详细信息请参阅LICENSE文件。



中文介绍

功能强大的 iOS 富文本编辑与显示框架。
(该项目是 YYKit 组件之一)

特性

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

架构

YYText 与 TextKit 架构对比

文本属性

YYText 原生支持的属性

演示 属性名
TextAttachment YYTextAttachment
TextHighlight YYTextHighlight
TextBinding YYTextBinding
TextShadow
TextInnerShadow
YYTextShadow
TextBorder YYTextBorder
TextBackgroundBorder YYTextBorder
TextBlockBorder YYTextBorder
TextGlyphTransform NSValue(CGAffineTransform)
TextUnderline YYTextDecoration
TextStrickthrough YYTextDecoration
TextBackedString YYTextBackedString

###YYText 支持的 CoreText 属性

<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/Alignment.png" width="200"></td>
  <td> TextAlignment </td>
  <td> NSParagraphStyle <br/>(NSTextAlignment) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/LineBreakMode.png" width="200"></td>
  <td> LineBreakMode </td>
  <td> NSParagraphStyle <br/>(NSLineBreakMode) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/LineSpacing.png" width="200"></td>
  <td> LineSpacing </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/ParagraphSpacing.png" width="200"></td>
  <td> ParagraphSpacing <br/> ParagraphSpacingBefore </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/FirstLineHeadIndent.png" width="200"></td>
  <td> FirstLineHeadIndent </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/HeadIndent.png" width="200"></td>
  <td> HeadIndent </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/TailIndent.png" width="200"></td>
  <td> TailIndent </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/MinimumLineHeight.png" width="200"></td>
  <td> MinimumLineHeight </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/MaximumLineHeight.png" width="200"></td>
  <td> MaximumLineHeight </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/LineHeightMultiple.png" width="200"></td>
  <td> LineHeightMultiple </td>
  <td> NSParagraphStyle <br/>(CGFloat) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/BaseWritingDirection.png" width="200"></td>
  <td> BaseWritingDirection </td>
  <td> NSParagraphStyle <br/>(NSWritingDirection) </td>
</tr>
<tr>
  <td><img src="https://raw.github.com/ibireme/YYText/master/Attributes/CoreText and TextKit/Paragraph/Tab.png" width="200"></td>
  <td> DefaultTabInterval <br/> TabStops </td>
  <td> NSParagraphStyle <br/>CGFloat/NSArray(NSTextTab)</td>
</tr>
演示 属性名
字体 UIFont(CTFontRef)
字距 NSNumber
描边宽度 NSNumber
描边颜色 CGColorRef
阴影 NSShadow
连字 NSNumber
垂直字形 NSNumber(BOOL)
书写方向 NSArray(NSNumber)
RunDelegate CTRunDelegateRef

用法

基本用法

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

调试

// 设置一个全局的 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];

更多示例

查看演示工程 Demo/YYTextDemo.xcodeproj



安装

CocoaPods

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

Carthage

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

手动安装

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

注意

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

文档

你可以在 CocoaDocs 查看在线 API 文档,也可以用 appledoc 本地生成文档。

系统要求

该项目最低支持 iOS 6.0Xcode 7.0

已知问题

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

许可证

YYText 使用的许可证为 MIT 许可证,详情见 LICENSE 文件。