YYText
Powerful text framework for iOS to display and edit rich text.
Features
- UILabel and UITextView API compatible
- High performance asynchronous text layout and rendering
- Extended CoreText attributes with more text effects
- Text attachments with UIImage, UIView and CALayer
- Custom highlight text range to allow user interact with
- Text parser support (built in markdown/emoticon parser)
- Text container path and exclusion paths support
- Vertical form layout support (for CJK text)
- Image and attributed text copy/paste support
- Attributed text placeholder support
- Custom keyboard view support
- Undo and redo control
- Attributed text archiver and unarchiver support
- Multi-language and VoiceOver support
- Interface Builder support
- Fully documented
Architecture
YYText vs TextKit
Text Attributes
YYText supported attributes
Demo | Attribute Name | Class |
---|---|---|
TextAttachment | YYTextAttachment | |
TextHighlight | YYTextHighlight | |
TextBinding | YYTextBinding | |
TextShadow TextInnerShadow |
YYTextShadow | |
TextBorder | YYTextBorder | |
TextBackgroundBorder | YYTextBorder | |
TextBlockBorder | YYTextBorder | |
TextGlyphTransform | NSValue(CGAffineTransform) | |
TextUnderline | YYTextDecoration | |
TextStrickthrough | YYTextDecoration | |
TextBackedString | YYTextBackedString |
CoreText attributes which is supported by YYText
Demo | Attribute Name | Class |
---|---|---|
Font | UIFont(CTFontRef) | |
Kern | NSNumber | |
StrokeWidth | NSNumber | |
StrokeColor | CGColorRef | |
Shadow | NSShadow | |
Ligature | NSNumber | |
VerticalGlyphForm | NSNumber(BOOL) | |
WritingDirection | NSArray(NSNumber) | |
RunDelegate | CTRunDelegateRef | |
TextAlignment | NSParagraphStyle (NSTextAlignment) |
|
LineBreakMode | NSParagraphStyle (NSLineBreakMode) |
|
LineSpacing | NSParagraphStyle (CGFloat) |
|
ParagraphSpacing ParagraphSpacingBefore |
NSParagraphStyle (CGFloat) |
|
FirstLineHeadIndent | NSParagraphStyle (CGFloat) |
|
HeadIndent | NSParagraphStyle (CGFloat) |
|
TailIndent | NSParagraphStyle (CGFloat) |
|
MinimumLineHeight | NSParagraphStyle (CGFloat) |
|
MaximumLineHeight | NSParagraphStyle (CGFloat) |
|
LineHeightMultiple | NSParagraphStyle (CGFloat) |
|
BaseWritingDirection | NSParagraphStyle (NSWritingDirection) |
|
DefaultTabInterval TabStops |
NSParagraphStyle CGFloat/NSArray(NSTextTab) |
Usage
Basic
// 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 = ...
Attributed text
// 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 highlight
You can use some convenience methods to set text highlight:
[text yy_setTextHighlightRange:range
color:[UIColor blueColor]
backgroundColor:[UIColor grayColor]
tapAction:^(UIView *containerView, NSAttributedString *text, NSRange range, CGRect rect){
NSLog(@"tap text range:...");
}];
Or set the text highlight with your custom config:
// 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:...");
}
Text attachments
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];
Text layout calculation
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;
Adjust text line position
// 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;
Asynchronous layout and rendering
// 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;
});
});
Text container control
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;
Text parser
// 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;
Debug
// 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];
More examples
See Demo/YYTextDemo.xcodeproj
for more examples:
Installation
CocoaPods
- Add
pod 'YYText'
to your Podfile. - Run
pod install
orpod update
. - Import <YYText/YYText.h>.
Carthage
- Add
github "ibireme/YYText"
to your Cartfile. - Run
carthage update --platform ios
and add the framework to your project. - Import <YYText/YYText.h>.
Manually
- Download all the files in the
YYText
subdirectory. - Add the source files to your Xcode project.
- Link with required frameworks:
- UIKit
- CoreFoundation
- CoreText
- QuartzCore
- Accelerate
- MobileCoreServices
- Import
YYText.h
.
Notice
You may add YYImage or YYWebImage to your project if you want to support animated image (GIF/APNG/WebP).
Documentation
Full API documentation is available on CocoaDocs.
You can also install documentation locally using appledoc.
Requirements
This library requires iOS 6.0+
and Xcode 8.0+
.