Initial commit

This commit is contained in:
ifish
2017-08-15 16:59:01 +08:00
commit bdc83e07ef
5766 changed files with 423223 additions and 0 deletions
@@ -0,0 +1,54 @@
//
// UMComMutiStyleTextView.h
// UMCommunity
//
// Created by umeng on 15-3-5.
// Copyright (c) 2015年 Umeng. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "UMComMutiText.h"
@class UMComMutiTextRunDelegate,UMComMutiTextRun,UMComMutiStyleTextView;
@class UMComMutiText;
@interface UMComMutiStyleTextView : UIView
@property (nonatomic, strong) NSMutableArray *checkWords;
@property (nonatomic, copy) void (^clickOnlinkText)(UMComMutiStyleTextView *mutiStyleTextView,UMComMutiTextRun *run);
@property (nonatomic,copy) NSString *text; // default is nil
@property (nonatomic,copy) NSMutableAttributedString *attributedText;
@property (nonatomic,strong) UIFont *font; // default is nil (system font 17 plain)
@property (nonatomic,strong) UIColor *textColor; // default is nil (text draws black)
@property (nonatomic,assign) CGFloat lineSpace;
@property (nonatomic,assign) CGPoint pointOffset;
@property (nonatomic) id framesetterRef;
@property (nonatomic,strong) NSArray *runs;
@property (nonatomic,strong) NSMutableDictionary *runRectDictionary;
@property (nonatomic,strong) UMComMutiTextRun *touchRun;
- (void)setMutiStyleTextViewWithMutiText:(UMComMutiText *)mutiText;
//+ (UMComMutiStyleTextView *)rectDictionaryWithSize:(CGSize)size
// font:(UIFont *)font
// attString:(NSString *)string
// lineSpace:(CGFloat )lineSpace
// runType:(UMComMutiTextRunTypeList)runType
// checkWords:(NSMutableArray *)checkWords;
@end
@@ -0,0 +1,393 @@
//
// UMComMutiStyleTextView.m
// UMCommunity
//
// Created by umeng on 15-3-5.
// Copyright (c) 2015年 Umeng. All rights reserved.
//
#import "UMComMutiStyleTextView.h"
#import "UMComResouceDefines.h"
#import <UMComFoundation/UMComKit+Color.h>
@interface UMComMutiStyleTextView ()
@end
@implementation UMComMutiStyleTextView
- (id)init
{
self = [self initWithFrame:CGRectZero];
return self;
}
- (void)dealloc
{
if (_framesetterRef) {
CFRelease((__bridge_retained CTFramesetterRef)(_framesetterRef));
_framesetterRef = NULL;
}
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self createDefault];
}
return self;
}
- (void)setMutiStyleTextViewWithMutiText:(UMComMutiText *)mutiText
{
self.attributedText = mutiText.attributedText;
self.framesetterRef = mutiText.framesetterRef;
self.runs = mutiText.runs;
self.font = mutiText.font;
self.lineSpace = mutiText.lineSpace;
self.textColor = mutiText.textColor;
[self setText:mutiText.text];
}
#pragma mark - CreateDefault
- (void)createDefault
{
//public
_text = nil;
_font = [UIFont systemFontOfSize:13.0f];
_textColor = [UIColor blackColor];
_lineSpace = 2.0f;
// self.heightOffset = 0.0f;
_attributedText = nil;
_pointOffset = CGPointZero;
//private
_runs = [NSMutableArray array];
_runRectDictionary = [NSMutableDictionary dictionary];
_touchRun = nil;
_checkWords = [NSMutableArray arrayWithCapacity:1];
_framesetterRef = NULL;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapInCerrentView:)];
[self addGestureRecognizer:tap];
}
#pragma mark - Set
- (void)setText:(NSString *)text
{
[self setNeedsDisplay];
_text = text;
}
- (void)awakeFromNib
{
[self createDefault];
}
#pragma mark - Draw Rect
- (void)drawRect:(CGRect)rect
{
//绘图上下文
CGContextRef contextRef = UIGraphicsGetCurrentContext();
if (self.attributedText == nil || self.attributedText.length == 0 ){
return;
}
CGRect viewRect = CGRectMake(self.pointOffset.x, -self.pointOffset.y, rect.size.width, rect.size.height);//
//修正坐标系
CGAffineTransform affineTransform = CGAffineTransformIdentity;
affineTransform = CGAffineTransformMakeTranslation(0.0, viewRect.size.height);
affineTransform = CGAffineTransformScale(affineTransform, 1.0, -1.0);
CGContextConcatCTM(contextRef, affineTransform);
//创建一个用来描画文字的路径,其区域为viewRect CGPath
CGMutablePathRef pathRef = CGPathCreateMutable();
CGPathAddRect(pathRef, NULL, viewRect);
CTFramesetterRef frameSetter = CFRetain((__bridge CTFramesetterRef)(self.framesetterRef));
CTFrameRef frameRef = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), pathRef, nil);
//通过context在frame中描画文字内容
CTFrameDraw(frameRef, contextRef);
[self.runRectDictionary removeAllObjects];
[self setRunsKeysToRunRectWithFrameRef:frameRef];
CGPathRelease(pathRef);
CFRelease(frameRef);
CFRelease(frameSetter);
}
- (void)setRunsKeysToRunRectWithFrameRef:(CTFrameRef)frameRef
{
CFArrayRef lines = CTFrameGetLines(frameRef);
CGPoint lineOrigins[CFArrayGetCount(lines)];
CTFrameGetLineOrigins(frameRef, CFRangeMake(0, 0), lineOrigins);
for (int i = 0; i < CFArrayGetCount(lines); i++)
{
CTLineRef lineRef= CFArrayGetValueAtIndex(lines, i);
CGFloat lineAscent;
CGFloat lineDescent;
CGFloat lineLeading;
CGPoint lineOrigin = CGPointMake(lineOrigins[i].x, lineOrigins[i].y);//
CTLineGetTypographicBounds(lineRef, &lineAscent, &lineDescent, &lineLeading);
CFArrayRef runs = CTLineGetGlyphRuns(lineRef);
for (int j = 0; j < CFArrayGetCount(runs); j++)
{
CTRunRef runRef = CFArrayGetValueAtIndex(runs, j);
CGFloat runAscent;
CGFloat runDescent;
CGRect runRect;
runRect.size.width = CTRunGetTypographicBounds(runRef, CFRangeMake(0,0), &runAscent, &runDescent, NULL);
runRect = CGRectMake(lineOrigin.x + CTLineGetOffsetForStringIndex(lineRef, CTRunGetStringRange(runRef).location, NULL),
lineOrigin.y,
runRect.size.width,
runAscent + runDescent);
NSDictionary * attributes = (__bridge NSDictionary *)CTRunGetAttributes(runRef);
UMComMutiTextRun *mutiTextRun = [attributes objectForKey:UMComMutiTextRunAttributedName];
if (mutiTextRun.drawSelf)
{
CGFloat runAscent,runDescent;
CGFloat runWidth = CTRunGetTypographicBounds(runRef, CFRangeMake(0,0), &runAscent, &runDescent, NULL);
CGFloat runHeight = (lineAscent + lineDescent );
CGFloat runPointX = runRect.origin.x + lineOrigin.x;
CGFloat runPointY = lineOrigin.y;
CGRect runRectDraw = CGRectMake(runPointX, runPointY, runWidth, runHeight);
[mutiTextRun drawRunWithRect:runRectDraw];
[self.runRectDictionary setObject:mutiTextRun forKey:[NSValue valueWithCGRect:runRectDraw]];
}
else
{
if (mutiTextRun)
{
[self.runRectDictionary setObject:mutiTextRun forKey:[NSValue valueWithCGRect:runRect]];
}
}
}
}
}
- (void)tapInCerrentView:(UITapGestureRecognizer *)tap
{
CGPoint location = [tap locationInView:self];
CGPoint runLocation = CGPointMake(location.x-self.pointOffset.x, self.frame.size.height - location.y+self.pointOffset.y+2);
__weak UMComMutiStyleTextView *weakSelf = self;
if (self.clickOnlinkText) {
if (self.runRectDictionary.count > 0) {
BOOL isInclude = NO;
for (NSValue *key in [self.runRectDictionary allKeys]) {
id object = [self.runRectDictionary objectForKey:key];
CGRect rect = [((NSValue *)key) CGRectValue];
if(CGRectContainsPoint(rect, runLocation))
{
isInclude = YES;
weakSelf.touchRun = (UMComMutiTextRun *)object;
if ([object isKindOfClass:[UMComMutiTextRunURL class]]) {
if (![[weakSelf.touchRun.text lowercaseString] hasPrefix:@"http"]) {
weakSelf.touchRun.text = [NSString stringWithFormat:@"http://%@",weakSelf.touchRun.text];
}
}
break;
}
}
if (isInclude == YES) {
weakSelf.clickOnlinkText(self,weakSelf.touchRun);
}else{
weakSelf.clickOnlinkText(self,nil);
}
}else{
weakSelf.clickOnlinkText(self,nil);
}
}
}
//#pragma mark -
//
//+ (NSMutableAttributedString *)createAttributedStringWithText:(NSString *)text font:(UIFont *)font lineSpace:(CGFloat)lineSpace
//{
// NSMutableAttributedString *attString = [[NSMutableAttributedString alloc] initWithString:text];
// //设置字体
// CTFontRef fontRef = CTFontCreateFromUIFont(font);
// [attString addAttribute:(NSString*)kCTFontAttributeName value:(__bridge id)fontRef range:NSMakeRange(0,attString.length)];
// CFRelease(fontRef);
//
// //添加换行模式
// CTParagraphStyleSetting lineBreakMode;
// CTLineBreakMode lineBreak = kCTLineBreakByWordWrapping;
// lineBreakMode.spec = kCTParagraphStyleSpecifierLineBreakMode;
// lineBreakMode.value = &lineBreak;
// lineBreakMode.valueSize = sizeof(lineBreak);
//
// //行距
// CTParagraphStyleSetting lineSpaceStyle;
// lineSpaceStyle.spec = kCTParagraphStyleSpecifierLineSpacing;
// lineSpaceStyle.valueSize = sizeof(lineSpace);
// lineSpaceStyle.value =&lineSpace;
//
// CTParagraphStyleSetting settings[] = {lineSpaceStyle,lineBreakMode};
// CTParagraphStyleRef style = CTParagraphStyleCreate(settings, sizeof(settings)/sizeof(settings[0]));
// NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithObject:(__bridge id)style forKey:(id)kCTParagraphStyleAttributeName ];
// CFRelease(style);
//
// [attString addAttributes:attributes range:NSMakeRange(0, [attString length])];
////
////
//// [attString addAttribute:(NSString*)kCTForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(0,attString.length)];
// return attString;
//}
//+ (NSArray *)createTextRunsWithAttString:(NSMutableAttributedString *)attString
// runType:(UMComMutiTextRunTypeList)type
// font:(UIFont *)font
// checkWords:(NSArray *)checkWords
//{
// NSMutableArray *array = [[NSMutableArray alloc] init];
// UIColor *blueColor = UMComColorWithHexString(FontColorBlue];
// if (type == UMComMutiTextRunFeedContentType || type == UMComMutiTextRunCommentType || type == UMComMutiTextRunLikeType || type == UMComMutiTextRunNoneType)
// {
// NSArray *subRunArray = [UMComMutiTextRunURL runsWithAttributedString:attString font:font textColor:blueColor];
// if (subRunArray.count > 0) {
// [array addObjectsFromArray:subRunArray];
// }
// subRunArray = [UMComMutiTextRunTopic runsWithAttributedString:attString font:font textColor:blueColor checkWords:checkWords];
// if (subRunArray.count > 0) {
// [array addObjectsFromArray:subRunArray];
// }
// subRunArray = [UMComMutiTextRunClickUser runsWithAttributedString:attString font:font textColor:blueColor checkWords:checkWords];
// if (subRunArray.count > 0) {
// [array addObjectsFromArray:subRunArray];
// }
// }
// return array;
//}
//- (NSArray *)runsWithattributString:(NSMutableAttributedString *)attribuString
// Font:(UIFont *)font
// lineSpace:(CGFloat )lineSpace
// color:(UIColor *)color
// checkWords:(NSArray *)checkWords
//{
// return nil;
//}
//+ (UMComMutiStyleTextView *)rectDictionaryWithSize:(CGSize)size
// font:(UIFont *)font
// attString:(NSString *)string
// lineSpace:(CGFloat )lineSpace
// runType:(UMComMutiTextRunTypeList)runType
// checkWords:(NSMutableArray *)checkWords
//{
// UMComMutiStyleTextView * styleTextView = [[UMComMutiStyleTextView alloc] init];
// styleTextView.checkWords = checkWords;
// styleTextView.font = font;
// styleTextView.lineSpace = lineSpace;
// [styleTextView rectDictionaryWithSize:size font:font attString:string lineSpace:lineSpace];
// return styleTextView;
//}
//- (void)rectDictionaryWithSize:(CGSize)size font:(UIFont *)font attString:(NSString *)string lineSpace:(CGFloat )lineSpace
//{
// if (!string || string.length == 0) {
// return;
// }
// CGFloat shortestLineWith = 0;
// int lineCount = 0;
// NSMutableAttributedString *attString = [[self class] createAttributedStringWithText:string font:font lineSpace:lineSpace];
// NSDictionary *dic = [attString attributesAtIndex:0 effectiveRange:nil];
// CTParagraphStyleRef paragraphStyle = (__bridge CTParagraphStyleRef)[dic objectForKey:(id)kCTParagraphStyleAttributeName];
// CGFloat linespace = 0;
//
// CTParagraphStyleGetValueForSpecifier(paragraphStyle, kCTParagraphStyleSpecifierLineSpacing, sizeof(linespace), &linespace);
//
// CGFloat height = 0;
// CGFloat width = 0;
// CFIndex lineIndex = 0;
//
// CGMutablePathRef pathRef = CGPathCreateMutable();
// CGPathAddRect(pathRef, NULL, CGRectMake(0, 0, size.width, size.height));
//
// NSArray *runs = [[self class] createTextRunsWithAttString:attString runType:0 font:font checkWords:self.checkWords];
// self.runs = runs;
//
// CFAttributedStringRef attStringRef = (__bridge CFAttributedStringRef)attString;
// CTFramesetterRef setterRef = CTFramesetterCreateWithAttributedString(attStringRef);
// self.framesetterRef = (__bridge_transfer id)(CFRetain(setterRef));
// CTFrameRef frameRef = CTFramesetterCreateFrame(setterRef, CFRangeMake(0, 0), pathRef, nil);
// CFArrayRef lines = CTFrameGetLines(frameRef);
//
// lineIndex = CFArrayGetCount(lines);
// lineCount = (int)lineIndex;
//
// CTLineRef lineRef;
// if (lineIndex > 1)
// {
// for (int i = 0; i <lineIndex ; i++)
// {
// lineRef= CFArrayGetValueAtIndex(lines, i);
// if (i == lineIndex - 1) {
// CGRect rect = CTLineGetBoundsWithOptions(lineRef,kCTLineBoundsExcludeTypographicShifts);
// shortestLineWith = rect.size.width;
// }
// CGFloat lineAscent;
// CGFloat lineDescent;
// CGFloat lineLeading;
// CTLineGetTypographicBounds(lineRef, &lineAscent, &lineDescent, &lineLeading);
//
// if (i == lineIndex - 1)
// {
// height += (lineAscent + lineDescent +linespace);
// }
// else
// {
// height += (lineAscent + lineDescent + linespace);
// }
// }
// width = size.width;
// }
// else
// {
// lineRef= CFArrayGetValueAtIndex(lines, 0);
// CGRect rect = CTLineGetBoundsWithOptions(lineRef,kCTLineBoundsExcludeTypographicShifts);
// shortestLineWith = rect.size.width;
//// self.lineHeight = rect.size.height + linespace;
// width = rect.size.width;
// CGFloat lineAscent;
// CGFloat lineDescent;
// CGFloat lineLeading;
// CTLineGetTypographicBounds(lineRef, &lineAscent, &lineDescent, &lineLeading);
//
// height += (lineAscent + lineDescent + lineLeading + linespace);
// height = height;
// }
//
//// self.totalHeight = height + lineSpace/2;
// self.attributedText = attString;
// CGPathRelease(pathRef);
// CFRelease(setterRef);
// CFRelease(frameRef);
//}
@end
@@ -0,0 +1,62 @@
//
// UMComMutiText.h
// UMCommunity
//
// Created by umeng on 16/5/4.
// Copyright © 2016年 Umeng. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "UMComMutiTextRun.h"
@interface UMComMutiText : NSObject
@property (nonatomic,copy) NSString *text; // default is nil
@property (nonatomic,strong) UIFont *font; // default is nil (system font 17 plain)
@property (nonatomic,strong) UIColor *textColor; // default is nil (text draws black)
@property (nonatomic,strong) UIColor *textHighLightColor;
@property (nonatomic,assign) CGFloat lineSpace;
@property (nonatomic,assign) NSInteger lineNumbers;
@property (nonatomic,assign) CGSize textSize;
@property (nonatomic,assign) CGPoint pointOffset;
@property (nonatomic,assign) NSLineBreakMode lineBreakMode;
@property (nonatomic,assign) NSInteger index;
@property (nonatomic,copy) NSMutableAttributedString *attributedText;
@property (nonatomic) id framesetterRef;
@property (nonatomic,strong) NSArray<UMComMutiTextRun *> *runs;
- (instancetype)initWithString:(NSString *)string;
- (instancetype)initWithAttributedString:(NSMutableAttributedString *)attributedString;
- (void)setTextColor:(UIColor *)color forRange:(NSRange)range;
- (void)setTextFont:(UIFont *)font forRange:(NSRange)range;
+ (UMComMutiText *)mutiTextWithSize:(CGSize)size
font:(UIFont *)font
string:(NSString *)string
lineSpace:(CGFloat)lineSpace
checkWords:(NSArray *)checkWords;
+ (UMComMutiText *)mutiTextWithSize:(CGSize)size
font:(UIFont *)font
string:(NSString *)string
lineSpace:(CGFloat)lineSpace
checkWords:(NSArray *)checkWords
textColor:(UIColor *)textColor;
+ (UMComMutiText *)mutiTextWithSize:(CGSize)size
font:(UIFont *)font
string:(NSString *)string
lineSpace:(CGFloat)lineSpace
checkWords:(NSArray *)checkWords
textColor:(UIColor *)textColor
highLightColor:(UIColor *)highLightColor;
@end
@@ -0,0 +1,294 @@
//
// UMComMutiText.m
// UMCommunity
//
// Created by umeng on 16/5/4.
// Copyright © 2016年 Umeng. All rights reserved.
//
#import "UMComMutiText.h"
#import "UMComResouceDefines.h"
#import <UMComFoundation/UMComKit+Color.h>
CTFontRef CTFontCreateFromUIFont(UIFont *font)
{
CTFontRef ctFont = CTFontCreateWithName((__bridge CFStringRef)font.fontName,
font.pointSize,
NULL);
return ctFont;
}
@interface UMComMutiText ()
@property (nonatomic, copy) void (^configTextCompletion)();
@property (nonatomic, copy) void (^configTextArrayCompletion)(NSArray *mutiTextArray);
@end
@implementation UMComMutiText
- (instancetype)init
{
self = [super init];
if (self) {
_text = nil;
_font = [UIFont systemFontOfSize:13.0f];
_textColor = [UIColor blackColor];
_lineSpace = 2.0f;
_attributedText = nil;
_pointOffset = CGPointZero;
//private
_runs = [NSMutableArray array];
_framesetterRef = NULL;
}
return self;
}
- (instancetype)initWithString:(NSString *)string
{
NSMutableAttributedString *attString = nil;
if (string && string.length > 0) {
attString = [[NSMutableAttributedString alloc] initWithString:string];
}
_text = string;
self = [self initWithAttributedString:attString];
if (self) {
}
return self;
}
- (instancetype)initWithAttributedString:(NSMutableAttributedString *)attributedString
{
self = [self init];
if (self) {
_attributedText = attributedString;
}
return self;
}
- (void)setFont:(UIFont *)font
{
_font = font;
[self setTextFont:font forRange:NSMakeRange(0,self.attributedText.length)];
}
- (void)setTextColor:(UIColor *)textColor
{
_textColor = textColor;
[self setTextColor:textColor forRange:NSMakeRange(0,self.attributedText.length)];
}
- (void)setTextFont:(UIFont *)font forRange:(NSRange)range
{
NSMutableAttributedString *attString = self.attributedText;
if ([attString isKindOfClass:[NSMutableAttributedString class]] && attString.length > 0) {
//设置字体
CTFontRef fontRef = CTFontCreateFromUIFont(font);//CTFontCreateWithName((__bridge CFStringRef)font.fontName, font.pointSize, NULL);
[attString addAttribute:(NSString*)kCTFontAttributeName value:(__bridge id)fontRef range:range];
CFRelease(fontRef);
}
}
- (void)setTextColor:(UIColor *)color forRange:(NSRange)range
{
if ([_attributedText isKindOfClass:[NSMutableAttributedString class]] && _attributedText.length > 0 && color) {
//设置颜色
[_attributedText addAttribute:(NSString*)kCTForegroundColorAttributeName value:color range:NSMakeRange(0,_attributedText.length)];
}
}
- (void)setLineSpace:(CGFloat)lineSpace
{
_lineSpace = lineSpace;
}
- (void)setLineBreakMode:(NSLineBreakMode)lineBreakMode
{
_lineBreakMode = lineBreakMode;
[self setLineBreakMode:lineBreakMode forRange:NSMakeRange(0, [_attributedText length])];
}
- (void)setLineBreakMode:(NSLineBreakMode)lineBreakMode forRange:(NSRange)range
{
}
+ (UMComMutiText *)mutiTextWithSize:(CGSize)size
font:(UIFont *)font
string:(NSString *)string
lineSpace:(CGFloat)lineSpace
checkWords:(NSArray *)checkWords
{
UMComMutiText *mutiText = [[UMComMutiText alloc]initWithString:string];
[mutiText setMutiTextWithSize:size font:font string:string lineSpace:lineSpace checkWords:checkWords];
mutiText.text = string;
return mutiText;
}
+ (UMComMutiText *)mutiTextWithSize:(CGSize)size
font:(UIFont *)font
string:(NSString *)string
lineSpace:(CGFloat)lineSpace
checkWords:(NSArray *)checkWords
textColor:(UIColor *)textColor
{
UMComMutiText *mutiText = [[UMComMutiText alloc]initWithString:string];
mutiText.textColor = textColor;
[mutiText setMutiTextWithSize:size font:font string:string lineSpace:lineSpace checkWords:checkWords];
mutiText.text = string;
return mutiText;
}
+ (UMComMutiText *)mutiTextWithSize:(CGSize)size
font:(UIFont *)font
string:(NSString *)string
lineSpace:(CGFloat)lineSpace
checkWords:(NSArray *)checkWords
textColor:(UIColor *)textColor
highLightColor:(UIColor *)highLightColor
{
UMComMutiText *mutiText = [[UMComMutiText alloc]initWithString:string];
mutiText.textHighLightColor = highLightColor;
mutiText.textColor = textColor;
[mutiText setMutiTextWithSize:size font:font string:string lineSpace:lineSpace checkWords:checkWords];
mutiText.text = string;
return mutiText;
}
- (void)setMutiTextWithSize:(CGSize)size
font:(UIFont *)font
string:(NSString *)string
lineSpace:(CGFloat)lineSpace
checkWords:(NSArray *)checkWords
{
self.font = font;
self.lineBreakMode = NSLineBreakByCharWrapping;
self.lineSpace = lineSpace;
[self reloadTextDataforRange:NSMakeRange(0, _attributedText.length)];
[self setHightLightAttributedTextWithSize:size checkWords:checkWords];
}
- (void)reloadTextDataforRange:(NSRange)range
{
if ([_attributedText isKindOfClass:[NSMutableAttributedString class]] && _attributedText.length > 0) {
CTLineBreakMode lineBreak = kCTLineBreakByWordWrapping;
switch (_lineBreakMode) {
case NSLineBreakByCharWrapping:
lineBreak = kCTLineBreakByCharWrapping;
break;
case NSLineBreakByClipping:
lineBreak = kCTLineBreakByClipping;
break;
case NSLineBreakByTruncatingHead:
lineBreak = kCTLineBreakByTruncatingHead;
break;
case NSLineBreakByTruncatingTail:
lineBreak = kCTLineBreakByTruncatingTail;
break;
case NSLineBreakByTruncatingMiddle:
lineBreak = kCTLineBreakByTruncatingMiddle;
break;
default:
lineBreak = kCTLineBreakByWordWrapping;
break;
}
CTParagraphStyleSetting settings[] = {
{kCTParagraphStyleSpecifierLineSpacing,sizeof(_lineSpace),&_lineSpace}, //行间距
{ kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof(CGFloat), &_lineSpace },//调整行间距
{ kCTParagraphStyleSpecifierMaximumLineSpacing, sizeof(CGFloat), &_lineSpace },//最大行间距
{ kCTParagraphStyleSpecifierMinimumLineSpacing, sizeof(CGFloat), &_lineSpace },//最小行间距
{kCTParagraphStyleSpecifierLineBreakMode,sizeof(lineBreak),&lineBreak},//换行模式
};
CTParagraphStyleRef style = CTParagraphStyleCreate(settings, sizeof(settings)/sizeof(settings[0]));
NSMutableDictionary *attributes = [NSMutableDictionary dictionaryWithObject:(__bridge id)style forKey:(id)kCTParagraphStyleAttributeName ];
CFRelease(style);
[_attributedText addAttributes:attributes range:range];
}
}
- (void)setHightLightAttributedTextWithSize:(CGSize)size checkWords:(NSArray *)checkWords
{
NSMutableAttributedString *attString = self.attributedText;
if (!attString || attString.length == 0) {
return;
}
CFIndex lineIndex = 0;
int lineCount = 0;
NSDictionary *dic = [attString attributesAtIndex:0 effectiveRange:nil];
CTParagraphStyleRef paragraphStyle = (__bridge CTParagraphStyleRef)[dic objectForKey:(id)kCTParagraphStyleAttributeName];
CGFloat linespace = 0;
CTParagraphStyleGetValueForSpecifier(paragraphStyle, kCTParagraphStyleSpecifierLineSpacing, sizeof(linespace), &linespace);
CGMutablePathRef pathRef = CGPathCreateMutable();
CGPathAddRect(pathRef, NULL, CGRectMake(0, 0, size.width, size.height));
UIColor *blueColor = UMComColorWithHexString(@"#507DAF");
if (!self.textHighLightColor) {
self.textHighLightColor = blueColor;
}
NSArray *runs = [[self class] createTextRunsWithAttString:attString font:_font highLightColor:self.textHighLightColor checkWords:checkWords];
self.runs = runs;
CFAttributedStringRef attStringRef = (__bridge CFAttributedStringRef)attString;
CTFramesetterRef setterRef = CTFramesetterCreateWithAttributedString(attStringRef);
self.framesetterRef = (__bridge_transfer id)(CFRetain(setterRef));
CTFrameRef frameRef = CTFramesetterCreateFrame(setterRef, CFRangeMake(0, 0), pathRef, nil);
CGSize textSize = CTFramesetterSuggestFrameSizeWithConstraints(setterRef, CFRangeMake(0, (CFIndex)[attString length]), NULL, size, NULL);
CFArrayRef lines = CTFrameGetLines(frameRef);
lineIndex = CFArrayGetCount(lines);
lineCount = (int)lineIndex;
self.lineNumbers = lineCount;
CTLineRef lineRef;
if (lineCount > 0) {
lineRef= CFArrayGetValueAtIndex(lines, lineCount-1);
CGRect rect = CTLineGetBoundsWithOptions(lineRef,kCTLineBoundsExcludeTypographicShifts);
if (lineCount == 1) {
textSize.width = rect.size.width+2;//宽度加两个像素以纠偏
}else{
textSize.width = size.width;
}
textSize.height += linespace;//高度加一行高度以纠偏
}
_textSize = textSize;
_attributedText = attString;
CGPathRelease(pathRef);
CFRelease(setterRef);
CFRelease(frameRef);
}
+ (NSArray *)createTextRunsWithAttString:(NSMutableAttributedString *)attString
font:(UIFont *)font
highLightColor:(UIColor *)color
checkWords:(NSArray *)checkWords
{
NSMutableArray *array = [[NSMutableArray alloc] init];
NSArray *subRunArray = [UMComMutiTextRunURL runsWithAttributedString:attString font:font textColor:color];
if (subRunArray.count > 0) {
[array addObjectsFromArray:subRunArray];
}
subRunArray = [UMComMutiTextRunTopic runsWithAttributedString:attString font:font textColor:color checkWords:checkWords];
if (subRunArray.count > 0) {
[array addObjectsFromArray:subRunArray];
}
subRunArray = [UMComMutiTextRunClickUser runsWithAttributedString:attString font:font textColor:color checkWords:checkWords];
if (subRunArray.count > 0) {
[array addObjectsFromArray:subRunArray];
}
return array;
}
@end
@@ -0,0 +1,151 @@
//
// UMComMutiTextRun.h
// UMCommunity
//
// Created by umeng on 15/8/19.
// Copyright (c) 2015年 Umeng. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <CoreText/CoreText.h>
typedef NS_OPTIONS(NSUInteger, UMComMutiTextRunTypeList)
{
UMComMutiTextRunNoneType = 0,
UMComMutiTextRunLikeType = 1,
UMComMutiTextRunCommentType = 2,
UMComMutiTextRunFeedContentType = 3,
};
extern NSString * const UMComMutiTextRunAttributedName;
//文字单元CTRun
@interface UMComMutiTextRun : UIResponder
/**
* 文本单元内容
*/
@property (nonatomic,copy ) NSString *text;
/**
* 文本单元字体
*/
@property (nonatomic,strong) UIFont *font;
/**
* 文本单元颜色
*/
@property (nonatomic,strong) UIColor *textColor;
/**
* 文本单元在字符串中的位置
*/
@property (nonatomic,assign) NSRange range;
/**
* 是否自己绘制自己
*/
@property(nonatomic,getter = isDrawSelf) BOOL drawSelf;
/**
* 向字符串中添加相关Run类型属性
*/
- (void)decorateToAttributedString:(NSMutableAttributedString *)attributedString range:(NSRange)range;
/**
* 绘制Run内容
*/
- (void)drawRunWithRect:(CGRect)rect;
/**
* 初始化方法
*/
- (id)initWithText:(NSString *)text
font:(UIFont *)font
textColor:(UIColor *)color
range:(NSRange)range;
@end
@interface UMComMutiTextRunClickUser : UMComMutiTextRun
/**
* 解析字符串中的“@userName ”格式内容生成Run对象
*
* @param attributedString 内容
*
* @param font 字体
*
* @param color 颜色
*
* @param checkWords 需要匹配的文字数组的文字
*
* @return UMComMutiTextRunClickUser对象数组
*/
+ (NSArray *)runsWithAttributedString:(NSMutableAttributedString *)attributedString
font:(UIFont *)font
textColor:(UIColor *)color
checkWords:(NSArray *)checkWords;
@end
@interface UMComMutiTextRunTopic : UMComMutiTextRun
/**
* 解析字符串中的“#话题#”格式内容生成Run对象
*
* @param attributedString 内容
*
* @param font 字体
*
* @param color 颜色
*
* @param checkWords 需要匹配的文字数组的文字
*
* @return UMComMutiTextRunTopic对象数组
*/
+ (NSArray *)runsWithAttributedString:(NSMutableAttributedString *)attributedString
font:(UIFont *)font
textColor:(UIColor *)color
checkWords:(NSArray *)checkWords;
@end
@interface UMComMutiTextRunURL : UMComMutiTextRun
/**
* 解析字符串中url内容生成Run对象
*
* @param attributedString 内容
*
* @param font 字体
*
* @param color 颜色
*
* @return UMComMutiTextRunURL对象数组
*/
+ (NSArray *)runsWithAttributedString:(NSMutableAttributedString *)attributedString
font:(UIFont *)font
textColor:(UIColor *)color;
@end
@interface UMComMutiTextRunDelegate : UMComMutiTextRun
@end
@interface UMComMutiTextRunEmoji : UMComMutiTextRunDelegate
+ (NSArray *)runsForAttributedString:(NSMutableAttributedString *)attributedString;
@end
@@ -0,0 +1,378 @@
//
// UMComMutiTextRun.m
// UMCommunity
//
// Created by umeng on 15/8/19.
// Copyright (c) 2015年 Umeng. All rights reserved.
//
#import "UMComMutiTextRun.h"
#import <CoreText/CoreText.h>
#import "UMComResouceDefines.h"
//#import <UMComDataStorage/UMComUser.h>
//#import <UMComDataStorage/UMComComment.h>
//#import <UMComDataStorage/UMComLike.h>
//#import <UMComDataStorage/UMComTopic.h>
//#import "UMComSyntaxHighlightTextStorage.h"
NSString * const UMComMutiTextRunAttributedName = @"UMComMutiTextRunAttributedName";
@implementation UMComMutiTextRun
/**
* 向字符串中添加相关Run类型属性
*/
- (void)decorateToAttributedString:(NSMutableAttributedString *)attributedString range:(NSRange)range
{
if (attributedString.length == 0) {
return;
}
[attributedString addAttribute:UMComMutiTextRunAttributedName value:self range:range];
[attributedString addAttribute:(NSString *)kCTForegroundColorAttributeName value:self.textColor range:range];
[attributedString addAttribute:(NSString *)kCTFontAttributeName value:self.font range:range];
// self.font = [attributedString attribute:NSFontAttributeName atIndex:0 longestEffectiveRange:nil inRange:range];
}
/**
* 绘制Run内容
*/
- (void)drawRunWithRect:(CGRect)rect
{
}
- (instancetype)initWithText:(NSString *)text
font:(UIFont *)font
textColor:(UIColor *)color
range:(NSRange)range
{
self = [self init];
if (self) {
self.text = text;
if ([font isKindOfClass:[UIFont class]]) {
self.font = font;
}
if ([color isKindOfClass:[UIColor class]]) {
self.textColor = color;
}
self.range = range;
}
return self;
}
- (instancetype)init
{
self = [super init];
if (self) {
self.font = [UIFont systemFontOfSize:15];
self.textColor = [UIColor blueColor];
self.drawSelf = NO;
}
return self;
}
@end
@implementation UMComMutiTextRunClickUser
- (void)decorateToAttributedString:(NSMutableAttributedString *)attributedString range:(NSRange)range
{
[super decorateToAttributedString:attributedString range:range];
// [attributedString addAttribute:(NSString *)kCTForegroundColorAttributeName value:self.textColor range:range];
}
+ (NSArray *)runsWithAttributedString:(NSMutableAttributedString *)attributedString
font:(UIFont *)font
textColor:(UIColor *)color
checkWords:(NSArray *)checkWords
{
NSString *string = attributedString.string;
NSMutableArray *array = [NSMutableArray array];
for (NSString *userName in checkWords) {
NSString *userNameRegulaStr = UserRulerString;
NSRegularExpression *regular = [NSRegularExpression regularExpressionWithPattern:userNameRegulaStr options:NSRegularExpressionDotMatchesLineSeparators error:nil];
NSInteger matchCount = [regular numberOfMatchesInString:userName options:0 range:NSMakeRange(0, [userName length])];
if (matchCount > 0) {
NSRegularExpression *userNameRegular = [NSRegularExpression regularExpressionWithPattern:userName options:NSRegularExpressionDotMatchesLineSeparators error:nil];
NSArray *matchs = [userNameRegular matchesInString:string
options:0
range:NSMakeRange(0, [string length])];
for (NSTextCheckingResult *match in matchs) {
UMComMutiTextRunClickUser *run = [[UMComMutiTextRunClickUser alloc] initWithText:userName font:font textColor:color range:match.range];
[run decorateToAttributedString:attributedString range:match.range];
[array addObject:run];
}
}
}
return array;
}
@end
@implementation UMComMutiTextRunTopic
/**
* 向字符串中添加相关Run类型属性
*/
- (void)decorateToAttributedString:(NSMutableAttributedString *)attributedString range:(NSRange)range
{
if (attributedString.length == 0) {
return;
}
[super decorateToAttributedString:attributedString range:range];
}
+ (NSArray *)runsWithAttributedString:(NSMutableAttributedString *)attributedString
font:(UIFont *)font
textColor:(UIColor *)color
checkWords:(NSArray *)checkWords
{
NSString *string = attributedString.string;
NSMutableArray *array = [NSMutableArray array];
for (NSString *topicName in checkWords) {
NSString *topicNameRegulaStr = TopicRulerString;
NSRegularExpression *regular = [NSRegularExpression regularExpressionWithPattern:topicNameRegulaStr options:NSRegularExpressionDotMatchesLineSeparators error:nil];
NSInteger matchCount = [regular numberOfMatchesInString:topicName options:0 range:NSMakeRange(0, [topicName length])];
if (matchCount > 0) {
NSRegularExpression *topicNameRegular = [NSRegularExpression regularExpressionWithPattern:topicName options:NSRegularExpressionDotMatchesLineSeparators error:nil];
NSArray *matchs = [topicNameRegular matchesInString:string
options:0
range:NSMakeRange(0, [string length])];
for (NSTextCheckingResult *match in matchs) {
UMComMutiTextRunTopic *run = [[UMComMutiTextRunTopic alloc] initWithText:topicName font:font textColor:color range:match.range];
[run decorateToAttributedString:attributedString range:match.range];
[array addObject:run];
}
}
}
return array;
}
@end
@implementation UMComMutiTextRunURL
/**
* 向字符串中添加相关Run类型属性
*/
- (void)decorateToAttributedString:(NSMutableAttributedString *)attributedString range:(NSRange)range
{
if (attributedString.length == 0) {
return;
}
[super decorateToAttributedString:attributedString range:range];
// [attributedString addAttribute:(NSString *)kCTForegroundColorAttributeName value:self.textColor range:range];
}
+ (NSArray *)runsWithAttributedString:(NSMutableAttributedString *)attributedString
font:(UIFont *)font
textColor:(UIColor *)color
{
NSString *string = attributedString.string;
NSMutableArray *array = [NSMutableArray array];
NSError *error = nil;
NSString *regulaStr = @"((http[s]{0,1}|ftp)://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\,\\.\\-~!@#$%^&*+?:_/=<>]*)?)|(www.[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\,\\.\\-~!@#$%^&*+?:_/=<>]*)?)";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regulaStr
options:NSRegularExpressionCaseInsensitive
error:&error];
if (error == nil)
{
NSArray *arrayOfAllMatches = [regex matchesInString:string
options:0
range:NSMakeRange(0, [string length])];
for (NSTextCheckingResult *match in arrayOfAllMatches)
{
NSString* substringForMatch = [string substringWithRange:match.range];
UMComMutiTextRunURL *run = [[UMComMutiTextRunURL alloc] initWithText:substringForMatch font:font textColor:color range:match.range];
[run decorateToAttributedString:attributedString range:match.range];
[array addObject:run ];
}
}
return array;
}
@end
@implementation UMComMutiTextRunDelegate
/**
* 向字符串中添加相关Run类型属性
*/
- (void)decorateToAttributedString:(NSMutableAttributedString *)attributedString range:(NSRange)range
{
[super decorateToAttributedString:attributedString range:range];
CTRunDelegateCallbacks callbacks;
callbacks.version = kCTRunDelegateVersion1;
callbacks.dealloc = UMComMutiTextRunDelegateDeallocCallback;
callbacks.getAscent = UMComMutiTextRunDelegateGetAscentCallback;
callbacks.getDescent = UMComMutiTextRunDelegateGetDescentCallback;
callbacks.getWidth = UMComMutiTextRunDelegateGetWidthCallback;
CTRunDelegateRef runDelegate = CTRunDelegateCreate(&callbacks, (__bridge void*)self);
[attributedString addAttribute:(NSString *)kCTRunDelegateAttributeName value:(__bridge id)runDelegate range:range];
CFRelease(runDelegate);
[attributedString addAttribute:(NSString *)kCTForegroundColorAttributeName value:(id)[UIColor clearColor].CGColor range:range];
}
#pragma mark - RunCallback
- (void)mutiTextRunDealloc
{
}
- (CGFloat)mutiTextRunGetAscent
{
return self.font.ascender;
}
- (CGFloat)mutiTextRunGetDescent
{
return self.font.descender;
}
- (CGFloat)mutiTextRunGetWidth
{
return self.font.ascender - self.font.descender;
}
#pragma mark - RunDelegateCallback
void UMComMutiTextRunDelegateDeallocCallback(void *refCon)
{
// UMComMutiTextRunDelegate *run =(__bridge UMComMutiTextRunDelegate *) refCon;
//
// [run mutiTextRunDealloc];
}
//--上行高度
CGFloat UMComMutiTextRunDelegateGetAscentCallback(void *refCon)
{
UMComMutiTextRunDelegate *run =(__bridge UMComMutiTextRunDelegate *) refCon;
return [run mutiTextRunGetAscent];
}
//--下行高度
CGFloat UMComMutiTextRunDelegateGetDescentCallback(void *refCon)
{
UMComMutiTextRunDelegate *run =(__bridge UMComMutiTextRunDelegate *) refCon;
return [run mutiTextRunGetDescent];
}
//-- 宽
CGFloat UMComMutiTextRunDelegateGetWidthCallback(void *refCon)
{
UMComMutiTextRunDelegate *run =(__bridge UMComMutiTextRunDelegate *) refCon;
return [run mutiTextRunGetWidth];
}
@end
@implementation UMComMutiTextRunEmoji
/**
* 返回表情数组
*/
+ (NSArray *) emojiStringArray
{
return [NSArray arrayWithObjects:@"[smile]",@"[cry]",@"[hei]",nil];
}
+ (NSArray *)runsForAttributedString:(NSMutableAttributedString *)attributedString
{
NSString *markL = @"[";
NSString *markR = @"]";
NSString *string = attributedString.string;
NSMutableArray *array = [NSMutableArray array];
NSMutableArray *stack = [NSMutableArray array];
for (int i = 0; i < string.length; i++)
{
NSString *s = [string substringWithRange:NSMakeRange(i, 1)];
if (([s isEqualToString:markL]) || ((stack.count > 0) && [stack[0] isEqualToString:markL]))
{
if (([s isEqualToString:markL]) && ((stack.count > 0) && [stack[0] isEqualToString:markL]))
{
[stack removeAllObjects];
}
[stack addObject:s];
if ([s isEqualToString:markR] || (i == string.length - 1))
{
NSMutableString *emojiStr = [[NSMutableString alloc] init];
for (NSString *c in stack)
{
[emojiStr appendString:c];
}
if ([[UMComMutiTextRunEmoji emojiStringArray] containsObject:emojiStr])
{
NSRange range = NSMakeRange(i + 1 - emojiStr.length, emojiStr.length);
[attributedString replaceCharactersInRange:range withString:@" "];
UMComMutiTextRunEmoji *run = [[UMComMutiTextRunEmoji alloc] init];
run.range = NSMakeRange(i + 1 - emojiStr.length, 1);
run.text = emojiStr;
run.drawSelf = YES;
[run decorateToAttributedString:attributedString range:run.range];
[array addObject:run];
}
[stack removeAllObjects];
}
}
}
return array;
}
/**
* 绘制Run内容
*/
- (void)drawRunWithRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
NSString *emojiString = [NSString stringWithFormat:@"%@.png",self.text];
UIImage *image = UMComImageWithImageName(emojiString);
if (image)
{
CGContextDrawImage(context, rect, image.CGImage);
}
}
@end