123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518 |
- //
- // YYTextAttribute.m
- // YYKit <https://github.com/ibireme/YYKit>
- //
- // Created by ibireme on 14/10/26.
- // Copyright (c) 2015 ibireme.
- //
- // This source code is licensed under the MIT-style license found in the
- // LICENSE file in the root directory of this source tree.
- //
- #import "YYTextAttribute.h"
- #import <UIKit/UIKit.h>
- #import <CoreText/CoreText.h>
- #import "NSObject+YYAdd.h"
- #import "NSAttributedString+YYText.h"
- #import "YYAnimatedImageView.h"
- #import "YYTextArchiver.h"
- #import "UIFont+YYAdd.h"
- #import "UIDevice+YYAdd.h"
- NSString *const YYTextBackedStringAttributeName = @"YYTextBackedString";
- NSString *const YYTextBindingAttributeName = @"YYTextBinding";
- NSString *const YYTextShadowAttributeName = @"YYTextShadow";
- NSString *const YYTextInnerShadowAttributeName = @"YYTextInnerShadow";
- NSString *const YYTextUnderlineAttributeName = @"YYTextUnderline";
- NSString *const YYTextStrikethroughAttributeName = @"YYTextStrikethrough";
- NSString *const YYTextBorderAttributeName = @"YYTextBorder";
- NSString *const YYTextBackgroundBorderAttributeName = @"YYTextBackgroundBorder";
- NSString *const YYTextBlockBorderAttributeName = @"YYTextBlockBorder";
- NSString *const YYTextAttachmentAttributeName = @"YYTextAttachment";
- NSString *const YYTextHighlightAttributeName = @"YYTextHighlight";
- NSString *const YYTextGlyphTransformAttributeName = @"YYTextGlyphTransform";
- NSString *const YYTextAttachmentToken = @"\uFFFC";
- NSString *const YYTextTruncationToken = @"\u2026";
- YYTextAttributeType YYTextAttributeGetType(NSString *name){
- if (name.length == 0) return YYTextAttributeTypeNone;
-
- static NSMutableDictionary *dic;
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- dic = [NSMutableDictionary new];
- NSNumber *All = @(YYTextAttributeTypeUIKit | YYTextAttributeTypeCoreText | YYTextAttributeTypeYYText);
- NSNumber *CoreText_YYText = @(YYTextAttributeTypeCoreText | YYTextAttributeTypeYYText);
- NSNumber *UIKit_YYText = @(YYTextAttributeTypeUIKit | YYTextAttributeTypeYYText);
- NSNumber *UIKit_CoreText = @(YYTextAttributeTypeUIKit | YYTextAttributeTypeCoreText);
- NSNumber *UIKit = @(YYTextAttributeTypeUIKit);
- NSNumber *CoreText = @(YYTextAttributeTypeCoreText);
- NSNumber *YYText = @(YYTextAttributeTypeYYText);
-
- dic[NSFontAttributeName] = All;
- dic[NSKernAttributeName] = All;
- dic[NSForegroundColorAttributeName] = UIKit;
- dic[(id)kCTForegroundColorAttributeName] = CoreText;
- dic[(id)kCTForegroundColorFromContextAttributeName] = CoreText;
- dic[NSBackgroundColorAttributeName] = UIKit;
- dic[NSStrokeWidthAttributeName] = All;
- dic[NSStrokeColorAttributeName] = UIKit;
- dic[(id)kCTStrokeColorAttributeName] = CoreText_YYText;
- dic[NSShadowAttributeName] = UIKit_YYText;
- dic[NSStrikethroughStyleAttributeName] = UIKit;
- dic[NSUnderlineStyleAttributeName] = UIKit_CoreText;
- dic[(id)kCTUnderlineColorAttributeName] = CoreText;
- dic[NSLigatureAttributeName] = All;
- dic[(id)kCTSuperscriptAttributeName] = UIKit; //it's a CoreText attrubite, but only supported by UIKit...
- dic[NSVerticalGlyphFormAttributeName] = All;
- dic[(id)kCTGlyphInfoAttributeName] = CoreText_YYText;
- dic[(id)kCTCharacterShapeAttributeName] = CoreText_YYText;
- dic[(id)kCTRunDelegateAttributeName] = CoreText_YYText;
- dic[(id)kCTBaselineClassAttributeName] = CoreText_YYText;
- dic[(id)kCTBaselineInfoAttributeName] = CoreText_YYText;
- dic[(id)kCTBaselineReferenceInfoAttributeName] = CoreText_YYText;
- dic[(id)kCTWritingDirectionAttributeName] = CoreText_YYText;
- dic[NSParagraphStyleAttributeName] = All;
-
- if (kiOS7Later) {
- dic[NSStrikethroughColorAttributeName] = UIKit;
- dic[NSUnderlineColorAttributeName] = UIKit;
- dic[NSTextEffectAttributeName] = UIKit;
- dic[NSObliquenessAttributeName] = UIKit;
- dic[NSExpansionAttributeName] = UIKit;
- dic[(id)kCTLanguageAttributeName] = CoreText_YYText;
- dic[NSBaselineOffsetAttributeName] = UIKit;
- dic[NSWritingDirectionAttributeName] = All;
- dic[NSAttachmentAttributeName] = UIKit;
- dic[NSLinkAttributeName] = UIKit;
- }
- if (kiOS8Later) {
- dic[(id)kCTRubyAnnotationAttributeName] = CoreText;
- }
-
- dic[YYTextBackedStringAttributeName] = YYText;
- dic[YYTextBindingAttributeName] = YYText;
- dic[YYTextShadowAttributeName] = YYText;
- dic[YYTextInnerShadowAttributeName] = YYText;
- dic[YYTextUnderlineAttributeName] = YYText;
- dic[YYTextStrikethroughAttributeName] = YYText;
- dic[YYTextBorderAttributeName] = YYText;
- dic[YYTextBackgroundBorderAttributeName] = YYText;
- dic[YYTextBlockBorderAttributeName] = YYText;
- dic[YYTextAttachmentAttributeName] = YYText;
- dic[YYTextHighlightAttributeName] = YYText;
- dic[YYTextGlyphTransformAttributeName] = YYText;
- });
- NSNumber *num = dic[name];
- if (num != nil) return num.integerValue;
- return YYTextAttributeTypeNone;
- }
- @implementation YYTextBackedString
- + (instancetype)stringWithString:(NSString *)string {
- YYTextBackedString *one = [self new];
- one.string = string;
- return one;
- }
- - (void)encodeWithCoder:(NSCoder *)aCoder {
- [aCoder encodeObject:self.string forKey:@"string"];
- }
- - (id)initWithCoder:(NSCoder *)aDecoder {
- self = [super init];
- _string = [aDecoder decodeObjectForKey:@"string"];
- return self;
- }
- - (id)copyWithZone:(NSZone *)zone {
- typeof(self) one = [self.class new];
- one.string = self.string;
- return one;
- }
- @end
- @implementation YYTextBinding
- + (instancetype)bindingWithDeleteConfirm:(BOOL)deleteConfirm {
- YYTextBinding *one = [self new];
- one.deleteConfirm = deleteConfirm;
- return one;
- }
- - (void)encodeWithCoder:(NSCoder *)aCoder {
- [aCoder encodeObject:@(self.deleteConfirm) forKey:@"deleteConfirm"];
- }
- - (id)initWithCoder:(NSCoder *)aDecoder {
- self = [super init];
- _deleteConfirm = ((NSNumber *)[aDecoder decodeObjectForKey:@"deleteConfirm"]).boolValue;
- return self;
- }
- - (id)copyWithZone:(NSZone *)zone {
- typeof(self) one = [self.class new];
- one.deleteConfirm = self.deleteConfirm;
- return one;
- }
- @end
- @implementation YYTextShadow
- + (instancetype)shadowWithColor:(UIColor *)color offset:(CGSize)offset radius:(CGFloat)radius {
- YYTextShadow *one = [self new];
- one.color = color;
- one.offset = offset;
- one.radius = radius;
- return one;
- }
- + (instancetype)shadowWithNSShadow:(NSShadow *)nsShadow {
- if (!nsShadow) return nil;
- YYTextShadow *shadow = [self new];
- shadow.offset = nsShadow.shadowOffset;
- shadow.radius = nsShadow.shadowBlurRadius;
- id color = nsShadow.shadowColor;
- if (color) {
- if (CGColorGetTypeID() == CFGetTypeID((__bridge CFTypeRef)(color))) {
- color = [UIColor colorWithCGColor:(__bridge CGColorRef)(color)];
- }
- if ([color isKindOfClass:[UIColor class]]) {
- shadow.color = color;
- }
- }
- return shadow;
- }
- - (NSShadow *)nsShadow {
- NSShadow *shadow = [NSShadow new];
- shadow.shadowOffset = self.offset;
- shadow.shadowBlurRadius = self.radius;
- shadow.shadowColor = self.color;
- return shadow;
- }
- - (void)encodeWithCoder:(NSCoder *)aCoder {
- [aCoder encodeObject:self.color forKey:@"color"];
- [aCoder encodeObject:@(self.radius) forKey:@"radius"];
- [aCoder encodeObject:[NSValue valueWithCGSize:self.offset] forKey:@"offset"];
- [aCoder encodeObject:self.subShadow forKey:@"subShadow"];
- }
- - (id)initWithCoder:(NSCoder *)aDecoder {
- self = [super init];
- _color = [aDecoder decodeObjectForKey:@"color"];
- _radius = ((NSNumber *)[aDecoder decodeObjectForKey:@"radius"]).floatValue;
- _offset = ((NSValue *)[aDecoder decodeObjectForKey:@"offset"]).CGSizeValue;
- _subShadow = [aDecoder decodeObjectForKey:@"subShadow"];
- return self;
- }
- - (id)copyWithZone:(NSZone *)zone {
- typeof(self) one = [self.class new];
- one.color = self.color;
- one.radius = self.radius;
- one.offset = self.offset;
- one.subShadow = self.subShadow.copy;
- return one;
- }
- @end
- @implementation YYTextDecoration
- - (instancetype)init {
- self = [super init];
- _style = YYTextLineStyleSingle;
- return self;
- }
- + (instancetype)decorationWithStyle:(YYTextLineStyle)style {
- YYTextDecoration *one = [self new];
- one.style = style;
- return one;
- }
- + (instancetype)decorationWithStyle:(YYTextLineStyle)style width:(NSNumber *)width color:(UIColor *)color {
- YYTextDecoration *one = [self new];
- one.style = style;
- one.width = width;
- one.color = color;
- return one;
- }
- - (void)encodeWithCoder:(NSCoder *)aCoder {
- [aCoder encodeObject:@(self.style) forKey:@"style"];
- [aCoder encodeObject:self.width forKey:@"width"];
- [aCoder encodeObject:self.color forKey:@"color"];
- }
- - (id)initWithCoder:(NSCoder *)aDecoder {
- self = [super init];
- self.style = ((NSNumber *)[aDecoder decodeObjectForKey:@"style"]).unsignedIntegerValue;
- self.width = [aDecoder decodeObjectForKey:@"width"];
- self.color = [aDecoder decodeObjectForKey:@"color"];
- return self;
- }
- - (id)copyWithZone:(NSZone *)zone {
- typeof(self) one = [self.class new];
- one.style = self.style;
- one.width = self.width;
- one.color = self.color;
- return one;
- }
- @end
- @implementation YYTextBorder
- + (instancetype)borderWithLineStyle:(YYTextLineStyle)lineStyle lineWidth:(CGFloat)width strokeColor:(UIColor *)color {
- YYTextBorder *one = [self new];
- one.lineStyle = lineStyle;
- one.strokeWidth = width;
- one.strokeColor = color;
- return one;
- }
- + (instancetype)borderWithFillColor:(UIColor *)color cornerRadius:(CGFloat)cornerRadius {
- YYTextBorder *one = [self new];
- one.fillColor = color;
- one.cornerRadius = cornerRadius;
- one.insets = UIEdgeInsetsMake(-2, 0, 0, -2);
- return one;
- }
- - (instancetype)init {
- self = [super init];
- self.lineStyle = YYTextLineStyleSingle;
- return self;
- }
- - (void)encodeWithCoder:(NSCoder *)aCoder {
- [aCoder encodeObject:@(self.lineStyle) forKey:@"lineStyle"];
- [aCoder encodeObject:@(self.strokeWidth) forKey:@"strokeWidth"];
- [aCoder encodeObject:self.strokeColor forKey:@"strokeColor"];
- [aCoder encodeObject:@(self.lineJoin) forKey:@"lineJoin"];
- [aCoder encodeObject:[NSValue valueWithUIEdgeInsets:self.insets] forKey:@"insets"];
- [aCoder encodeObject:@(self.cornerRadius) forKey:@"cornerRadius"];
- [aCoder encodeObject:self.shadow forKey:@"shadow"];
- [aCoder encodeObject:self.fillColor forKey:@"fillColor"];
- }
- - (id)initWithCoder:(NSCoder *)aDecoder {
- self = [super init];
- _lineStyle = ((NSNumber *)[aDecoder decodeObjectForKey:@"lineStyle"]).unsignedIntegerValue;
- _strokeWidth = ((NSNumber *)[aDecoder decodeObjectForKey:@"strokeWidth"]).doubleValue;
- _strokeColor = [aDecoder decodeObjectForKey:@"strokeColor"];
- _lineJoin = (CGLineJoin)((NSNumber *)[aDecoder decodeObjectForKey:@"join"]).unsignedIntegerValue;
- _insets = ((NSValue *)[aDecoder decodeObjectForKey:@"insets"]).UIEdgeInsetsValue;
- _cornerRadius = ((NSNumber *)[aDecoder decodeObjectForKey:@"cornerRadius"]).doubleValue;
- _shadow = [aDecoder decodeObjectForKey:@"shadow"];
- _fillColor = [aDecoder decodeObjectForKey:@"fillColor"];
- return self;
- }
- - (id)copyWithZone:(NSZone *)zone {
- typeof(self) one = [self.class new];
- one.lineStyle = self.lineStyle;
- one.strokeWidth = self.strokeWidth;
- one.strokeColor = self.strokeColor;
- one.lineJoin = self.lineJoin;
- one.insets = self.insets;
- one.cornerRadius = self.cornerRadius;
- one.shadow = self.shadow.copy;
- one.fillColor = self.fillColor;
- return one;
- }
- @end
- @implementation YYTextAttachment
- + (instancetype)attachmentWithContent:(id)content {
- YYTextAttachment *one = [self new];
- one.content = content;
- return one;
- }
- - (void)encodeWithCoder:(NSCoder *)aCoder {
- [aCoder encodeObject:self.content forKey:@"content"];
- [aCoder encodeObject:[NSValue valueWithUIEdgeInsets:self.contentInsets] forKey:@"contentInsets"];
- [aCoder encodeObject:self.userInfo forKey:@"userInfo"];
- }
- - (id)initWithCoder:(NSCoder *)aDecoder {
- self = [super init];
- _content = [aDecoder decodeObjectForKey:@"content"];
- _contentInsets = ((NSValue *)[aDecoder decodeObjectForKey:@"contentInsets"]).UIEdgeInsetsValue;
- _userInfo = [aDecoder decodeObjectForKey:@"userInfo"];
- return self;
- }
- - (id)copyWithZone:(NSZone *)zone {
- typeof(self) one = [self.class new];
- if ([self.content respondsToSelector:@selector(copy)]) {
- one.content = [self.content copy];
- } else {
- one.content = self.content;
- }
- one.contentInsets = self.contentInsets;
- one.userInfo = self.userInfo.copy;
- return one;
- }
- @end
- @implementation YYTextHighlight
- + (instancetype)highlightWithAttributes:(NSDictionary *)attributes {
- YYTextHighlight *one = [self new];
- one.attributes = attributes;
- return one;
- }
- + (instancetype)highlightWithBackgroundColor:(UIColor *)color {
- YYTextBorder *highlightBorder = [YYTextBorder new];
- highlightBorder.insets = UIEdgeInsetsMake(-2, -1, -2, -1);
- highlightBorder.cornerRadius = 3;
- highlightBorder.fillColor = color;
-
- YYTextHighlight *one = [self new];
- [one setBackgroundBorder:highlightBorder];
- return one;
- }
- - (void)setAttributes:(NSDictionary *)attributes {
- _attributes = attributes.mutableCopy;
- }
- - (void)encodeWithCoder:(NSCoder *)aCoder {
- NSData *data = nil;
- @try {
- data = [YYTextArchiver archivedDataWithRootObject:self.attributes];
- }
- @catch (NSException *exception) {
- NSLog(@"%@",exception);
- }
- [aCoder encodeObject:data forKey:@"attributes"];
- }
- - (id)initWithCoder:(NSCoder *)aDecoder {
- self = [super init];
- NSData *data = [aDecoder decodeObjectForKey:@"attributes"];
- @try {
- _attributes = [YYTextUnarchiver unarchiveObjectWithData:data];
- }
- @catch (NSException *exception) {
- NSLog(@"%@",exception);
- }
- return self;
- }
- - (id)copyWithZone:(NSZone *)zone {
- typeof(self) one = [self.class new];
- one.attributes = self.attributes.mutableCopy;
- return one;
- }
- - (void)_makeMutableAttributes {
- if (!_attributes) {
- _attributes = [NSMutableDictionary new];
- } else if (![_attributes isKindOfClass:[NSMutableDictionary class]]) {
- _attributes = _attributes.mutableCopy;
- }
- }
- - (void)setFont:(UIFont *)font {
- [self _makeMutableAttributes];
- if (font == (id)[NSNull null] || font == nil) {
- ((NSMutableDictionary *)_attributes)[(id)kCTFontAttributeName] = [NSNull null];
- } else {
- CTFontRef ctFont = [font CTFontRef];
- if (ctFont) {
- ((NSMutableDictionary *)_attributes)[(id)kCTFontAttributeName] = (__bridge id)(ctFont);
- CFRelease(ctFont);
- }
- }
- }
- - (void)setColor:(UIColor *)color {
- [self _makeMutableAttributes];
- if (color == (id)[NSNull null] || color == nil) {
- ((NSMutableDictionary *)_attributes)[(id)kCTForegroundColorAttributeName] = [NSNull null];
- ((NSMutableDictionary *)_attributes)[NSForegroundColorAttributeName] = [NSNull null];
- } else {
- ((NSMutableDictionary *)_attributes)[(id)kCTForegroundColorAttributeName] = (__bridge id)(color.CGColor);
- ((NSMutableDictionary *)_attributes)[NSForegroundColorAttributeName] = color;
- }
- }
- - (void)setStrokeWidth:(NSNumber *)width {
- [self _makeMutableAttributes];
- if (width == (id)[NSNull null] || width == nil) {
- ((NSMutableDictionary *)_attributes)[(id)kCTStrokeWidthAttributeName] = [NSNull null];
- } else {
- ((NSMutableDictionary *)_attributes)[(id)kCTStrokeWidthAttributeName] = width;
- }
- }
- - (void)setStrokeColor:(UIColor *)color {
- [self _makeMutableAttributes];
- if (color == (id)[NSNull null] || color == nil) {
- ((NSMutableDictionary *)_attributes)[(id)kCTStrokeColorAttributeName] = [NSNull null];
- ((NSMutableDictionary *)_attributes)[NSStrokeColorAttributeName] = [NSNull null];
- } else {
- ((NSMutableDictionary *)_attributes)[(id)kCTStrokeColorAttributeName] = (__bridge id)(color.CGColor);
- ((NSMutableDictionary *)_attributes)[NSStrokeColorAttributeName] = color;
- }
- }
- - (void)setTextAttribute:(NSString *)attribute value:(id)value {
- [self _makeMutableAttributes];
- if (value == nil) value = [NSNull null];
- ((NSMutableDictionary *)_attributes)[attribute] = value;
- }
- - (void)setShadow:(YYTextShadow *)shadow {
- [self setTextAttribute:YYTextShadowAttributeName value:shadow];
- }
- - (void)setInnerShadow:(YYTextShadow *)shadow {
- [self setTextAttribute:YYTextInnerShadowAttributeName value:shadow];
- }
- - (void)setUnderline:(YYTextDecoration *)underline {
- [self setTextAttribute:YYTextUnderlineAttributeName value:underline];
- }
- - (void)setStrikethrough:(YYTextDecoration *)strikethrough {
- [self setTextAttribute:YYTextStrikethroughAttributeName value:strikethrough];
- }
- - (void)setBackgroundBorder:(YYTextBorder *)border {
- [self setTextAttribute:YYTextBackgroundBorderAttributeName value:border];
- }
- - (void)setBorder:(YYTextBorder *)border {
- [self setTextAttribute:YYTextBorderAttributeName value:border];
- }
- - (void)setAttachment:(YYTextAttachment *)attachment {
- [self setTextAttribute:YYTextAttachmentAttributeName value:attachment];
- }
- @end
|