JXEmoji.m 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038
  1. //
  2. // JXEmoji.m
  3. // sjvodios
  4. //
  5. // Created by jixiong on 13-7-9.
  6. //
  7. //
  8. #import "JXEmoji.h"
  9. #import "FaceViewController.h"
  10. #import "emojiViewController.h"
  11. #import "webpageVC.h"
  12. #import "JXActionSheetVC.h"
  13. #import <CoreText/CoreText.h>
  14. @interface JXEmoji () <JXActionSheetVCDelegate>
  15. @property (nonatomic, strong) JXActionSheetVC *actionVC;
  16. @end
  17. @implementation JXEmoji
  18. @synthesize maxWidth,faceHeight,faceWidth,offset;
  19. #define BEGIN_FLAG @"["
  20. #define END_FLAG @"]"
  21. #define AT_FLAG @"@"
  22. static NSMutableArray *faceArray;
  23. static NSMutableArray *imageArrayC;
  24. static NSMutableArray *imageArrayE;
  25. static NSMutableArray *shortNameArrayC;
  26. static NSMutableArray *shortNameArrayE;
  27. - (id)initWithFrame:(CGRect)frame
  28. {
  29. self = [super initWithFrame:frame];
  30. if (self) {
  31. if(shortNameArrayC==nil){
  32. /*
  33. faceArray = [[NSArray alloc]initWithObjects:@"[微笑]",@"[撇嘴]",@"[色]",@"[发呆]",@"[得意]",@"[流泪]",@"[害羞]",@"[闭嘴]",@"[睡]",@"[大哭]",
  34. @"[尴尬]",@"[发怒]",@"[调皮]",@"[龇牙]",@"[惊讶]",@"[难过]",@"[严肃]",@"[冷汗]",@"[抓狂]",@"[吐]",@"[偷笑]",@"[可爱]",@"[白眼]",@"[傲慢]",
  35. @"[饥饿]",@"[困]",@"[惊恐]",@"[流汗]",@"[憨笑]",@"[大兵]",@"[奋斗]",@"[咒骂]",@"[疑问]",@"[嘘]",@"[晕]",@"[折磨]",@"[衰]",@"[骷髅]",
  36. @"[敲打]",@"[再见]",@"[擦汗]",@"[抠鼻]",@"[鼓掌]",@"[糗大了]",@"[坏笑]",@"[左哼哼]",@"[右哼哼]",@"[哈欠]",@"[鄙视]",@"[委屈]",@"[快哭了]",
  37. @"[阴险]",@"[亲嘴]",@"[吓]",@"[可怜]",@"[菜刀]",@"[西瓜]",@"[啤酒]",@"[篮球]",@"[乒乓]",@"[咖啡]",@"[饭]",@"[猪头]",@"[玫瑰]",@"[凋谢]",
  38. @"[示爱]",@"[爱心]",@"[心碎]",@"[蛋糕]",@"[闪电]",@"[炸弹]",@"[刀]",@"[足球]",@"[瓢虫]",@"[便便]",@"[拥抱]",@"[月亮]",@"[太阳]",@"[礼物]",
  39. @"[强]",@"[弱]",@"[握手]",@"[胜利]",@"[抱拳]",@"[勾引]",@"[拳头]",@"[差劲]",@"[爱你]",@"[NO]",@"[OK]",@"[苹果]",@"[可爱狗]",@"[小熊]",@"[彩虹]",@"[皇冠]",@"[钻石]",nil];
  40. imageArray = [[NSMutableArray alloc] init];
  41. for (int i = 0;i<[faceArray count];i++){
  42. // NSString* s = [NSString stringWithFormat:@"%@f%.3d.png",[self imageFilePath],i];
  43. NSString* s = [NSString stringWithFormat:@"f%.3d.png",i];
  44. [imageArray addObject:s];
  45. }*/
  46. // faceArray = g_faceVC.faceArray;
  47. // imageArrayC = g_faceVC.imageArrayC;
  48. // imageArrayE = g_faceVC.imageArrayE;
  49. shortNameArrayC = g_faceVC.shortNameArrayC;
  50. shortNameArrayE = g_faceVC.shortNameArrayE;
  51. }
  52. data = [[NSMutableArray alloc] init];
  53. faceWidth = 23;
  54. faceHeight = 23;
  55. _top = 0;
  56. offset = 0;
  57. maxWidth = JX_SCREEN_WIDTH-INSETS-HEAD_SIZE - 100;
  58. self.numberOfLines = 0;
  59. self.lineBreakMode = NSLineBreakByWordWrapping;
  60. self.textAlignment = NSTextAlignmentLeft;
  61. self.userInteractionEnabled = YES;
  62. }
  63. return self;
  64. }
  65. -(void)dealloc{
  66. // [data release];
  67. // [super dealloc];
  68. }
  69. /*
  70. -(void) drawRect:(CGRect)rect
  71. {
  72. [self.textColor set];
  73. // if( [data count]==1){
  74. // if (![self.text hasPrefix:BEGIN_FLAG] && ![self.text hasSuffix:END_FLAG]){
  75. // [super drawRect:rect];
  76. // return;
  77. // }
  78. // }
  79. CGFloat upX=0;
  80. CGFloat upY=0;
  81. CGFloat height = 0;
  82. // NSLog(@"%f,%f,%f,%f",rect.origin.x,rect.origin.y,rect.size.width,rect.size.height);
  83. for (int i=0;i<[data count];i++) {
  84. NSString *str=[data objectAtIndex:i];
  85. unsigned long n = NSNotFound;
  86. if ([str hasPrefix:BEGIN_FLAG]&&[str hasSuffix:END_FLAG]) {
  87. n = [shortNameArrayC indexOfObject:str];
  88. if(n != NSNotFound){
  89. // NSString *imageName = [imageArrayC objectAtIndex:n];
  90. NSDictionary *dic = [g_constant.emojiArray objectAtIndex:n];
  91. NSString *imageName = dic[@"filename"];
  92. UIImage *img=[UIImage imageNamed:imageName];
  93. if ((faceWidth+upX) >= maxWidth)
  94. {
  95. upY = upY + height;
  96. upX = 0;
  97. }
  98. //
  99. [img drawInRect:CGRectMake(upX, upY+_top, faceWidth, faceHeight)];
  100. // NSLog(@"%@,%f,%f",str,upX,upY);
  101. upX=faceWidth+upX;
  102. height = faceHeight;
  103. }else {
  104. n = [shortNameArrayE indexOfObject:str];
  105. if(n != NSNotFound){
  106. // NSString *imageName = [imageArrayC objectAtIndex:n];
  107. NSDictionary *dic = [g_constant.emojiArray objectAtIndex:n];
  108. NSString *imageName = dic[@"filename"];
  109. UIImage *img=[UIImage imageNamed:imageName];
  110. if ((faceWidth+upX) >= maxWidth)
  111. {
  112. upY = upY + height;
  113. upX = 0;
  114. height = 0;
  115. }
  116. [img drawInRect:CGRectMake(upX, upY+_top, faceWidth, faceHeight)];
  117. upX=faceWidth+upX;
  118. height = faceHeight;
  119. // NSLog(@"%@,%f,%f",str,upX,upY);
  120. }
  121. }
  122. }
  123. if(n == NSNotFound){
  124. NSArray *arr = [self setTextWithLinkAttribute:str];
  125. for (int j = 0; j < [str length]; j++) {
  126. NSString *temp = [str substringWithRange:NSMakeRange(j, 1)];
  127. CGSize size = [temp boundingRectWithSize:CGSizeMake(_size, _size) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:self.font} context:nil].size;
  128. if([temp isEqualToString:@"\n"] || [temp isEqualToString:@"\r"]){
  129. upY = upY + 20;
  130. upX = 0;
  131. }else{
  132. // CGSize size=[temp sizeWithFont:self.font constrainedToSize:CGSizeMake(_size, _size)];
  133. // CGSize size = [temp boundingRectWithSize:CGSizeMake(_size, _size) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:self.font} context:nil].size;
  134. if ((upX+size.width) >= maxWidth)
  135. {
  136. // upY = upY + size.height;
  137. upY = upY + size.height;;
  138. upX = 0;
  139. height = 0;
  140. }
  141. // [temp drawInRect:CGRectMake(upX, upY+_top + 3, size.width, size.height) withFont:self.font];
  142. BOOL flag = NO;
  143. for (NSInteger i = 0; i < arr.count; i ++) {
  144. NSRange range = [arr[i] rangeValue];
  145. if (j >= range.location && j < range.length + range.location) {
  146. flag = YES;
  147. break;
  148. }
  149. }
  150. if (flag) {
  151. [temp drawInRect:CGRectMake(upX, upY+_top + 3, size.width, size.height) withAttributes:@{NSFontAttributeName:self.font, NSForegroundColorAttributeName:[UIColor blueColor]}];
  152. }else {
  153. [temp drawInRect:CGRectMake(upX, upY+_top + 3, size.width, size.height) withAttributes:@{NSFontAttributeName:self.font, NSForegroundColorAttributeName:[UIColor blackColor]}];
  154. }
  155. upX=upX+size.width;
  156. if (height != faceHeight) {
  157. height = _size;
  158. }
  159. }
  160. // NSLog(@"%@,%f,%f",temp,upX,upY);
  161. }
  162. }
  163. }
  164. }
  165. */
  166. //判断是否含有表情
  167. - (BOOL)isContainsEmoji:(NSString *)string {
  168. __block BOOL isEomji = NO;
  169. [string enumerateSubstringsInRange:NSMakeRange(0, [string length]) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
  170. const unichar hs = [substring characterAtIndex:0];
  171. // surrogate pair
  172. if (0xd800 <= hs && hs <= 0xdbff) {
  173. if (substring.length > 1) {
  174. const unichar ls = [substring characterAtIndex:1];
  175. const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
  176. if (0x1d000 <= uc && uc <= 0x1f77f) {
  177. isEomji = YES;
  178. }
  179. }
  180. } else {
  181. // non surrogate
  182. if (0x2100 <= hs && hs <= 0x27ff && hs != 0x263b) {
  183. isEomji = YES;
  184. } else if (0x2B05 <= hs && hs <= 0x2b07) {
  185. isEomji = YES;
  186. } else if (0x2934 <= hs && hs <= 0x2935) {
  187. isEomji = YES;
  188. } else if (0x3297 <= hs && hs <= 0x3299) {
  189. isEomji = YES;
  190. } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50|| hs == 0x231a ) {
  191. isEomji = YES;
  192. }
  193. if (!isEomji && substring.length > 1) {
  194. const unichar ls = [substring characterAtIndex:1];
  195. if (ls == 0x20e3) {
  196. isEomji = YES;
  197. }
  198. }
  199. }
  200. }];
  201. return isEomji;
  202. }
  203. //将表情和文字分开,装进array
  204. -(void)getImageRange:(NSString*)message array: (NSMutableArray*)array {
  205. NSRange range=[message rangeOfString: BEGIN_FLAG];
  206. NSRange range1=[message rangeOfString: END_FLAG];
  207. NSRange atRange = [message rangeOfString:AT_FLAG];
  208. //判断当前字符串是否还有表情的标志。
  209. self.contentEmoji = [self isContainsEmoji:message];
  210. if (((range.length>0 && range1.length>0) || atRange.length>0) && range1.location > range.location) {
  211. if (range.length>0 && range1.length>0) {
  212. // self.contentEmoji = YES;
  213. // if (range.location > 0) {
  214. // [array addObject:[message substringToIndex:range.location]];
  215. // [array addObject:[message substringWithRange:NSMakeRange(range.location, range1.location+1-range.location)]];
  216. // NSString *str=[message substringFromIndex:range1.location+1];
  217. // [self getImageRange:str array:array];
  218. // }else {
  219. // NSString *nextstr=[message substringWithRange:NSMakeRange(range.location, range1.location+1-range.location)];
  220. // //排除文字是“”的
  221. // if (![nextstr isEqualToString:@""]) {
  222. // [array addObject:nextstr];
  223. // NSString *str=[message substringFromIndex:range1.location+1];
  224. // [self getImageRange:str array:array];
  225. // }else {
  226. // return;
  227. // }
  228. // }
  229. if (range.location > 0) {
  230. NSString *str = [message substringToIndex:range.location];
  231. NSString *str1 = [message substringFromIndex:range.location];
  232. [array addObject:str];
  233. [self getImageRange:str1 array:array];
  234. }else {
  235. NSString *emojiString = [message substringWithRange:NSMakeRange(range.location + 1, range1.location - 1)];
  236. BOOL isEmoji = NO;
  237. NSString *str;
  238. NSString *str1;
  239. for (NSMutableDictionary *dic in g_constant.emojiArray) {
  240. NSString *emoji = [dic objectForKey:@"english"];
  241. if ([emoji isEqualToString:emojiString]) {
  242. isEmoji = YES;
  243. break;
  244. }
  245. }
  246. if (isEmoji) {
  247. self.contentEmoji = YES;
  248. str = [message substringWithRange:NSMakeRange(range.location, range1.location + 1)];
  249. str1 = [message substringFromIndex:range1.location + 1];
  250. [array addObject:str];
  251. }else{
  252. NSString *posString = [message substringWithRange:NSMakeRange(range.location + 1, range1.location)];
  253. NSRange posRange = [posString rangeOfString:@"["];
  254. if (posRange.location != NSNotFound) {
  255. str = [message substringToIndex:posRange.location + 1];
  256. str1 = [message substringFromIndex:posRange.location + 1];
  257. [array addObject:str];
  258. }else{
  259. str = [message substringToIndex:range1.location + 1];
  260. str1 = [message substringFromIndex:range1.location + 1];
  261. [array addObject:str];
  262. }
  263. }
  264. [self getImageRange:str1 array:array];
  265. }
  266. } else if (atRange.length>0) {
  267. if (atRange.location > 0) {
  268. [array addObject:[message substringToIndex:atRange.location]];
  269. [array addObject:[message substringWithRange:NSMakeRange(atRange.location, 1)]];
  270. NSString *str=[message substringFromIndex:atRange.location+1];
  271. [self getImageRange:str array:array];
  272. }else{
  273. [array addObject:[message substringWithRange:NSMakeRange(atRange.location, 1)]];
  274. NSString *str=[message substringFromIndex:atRange.location+1];
  275. [self getImageRange:str array:array];
  276. }
  277. }else if (message != nil) {
  278. [array addObject:message];
  279. }
  280. }
  281. else if (range.length>0 && range1.length>0 && range1.location < range.location){
  282. NSString *str = [message substringToIndex:range1.location + 1];
  283. NSString *str1 = [message substringFromIndex:range1.location + 1];
  284. [array addObject:str];
  285. [self getImageRange:str1 array:array];
  286. }
  287. else if (message != nil) {
  288. [array addObject:message];
  289. }
  290. }
  291. //获取特殊文本的范围
  292. #pragma mark ------------特殊字符-----------------
  293. -(void)setAttributedTextRange:(NSString *)text{
  294. NSError *error = NULL;
  295. NSString * patren = @"[^0-9]";
  296. NSRegularExpression * reg = [NSRegularExpression regularExpressionWithPattern:patren options:0 error:&error];
  297. NSString * numberString = [reg stringByReplacingMatchesInString:text options:0 range:NSMakeRange(0, text.length) withTemplate:@" "];
  298. //提取所有数字串
  299. NSArray * array = [numberString componentsSeparatedByString:@" "];
  300. NSMutableArray * numberArr = [[NSMutableArray alloc]init];
  301. //除去空格,并在手机号前后加空格
  302. NSMutableString * muText = [[NSMutableString alloc]initWithString:text];
  303. //因为插入空格后位置发生变化
  304. int plus = 0;
  305. for (int i = 0; i < [array count]; i++) {
  306. NSString * number = array[i];
  307. if (![number isEqualToString:@""] && number.length >5) {
  308. NSRange range = [text rangeOfString:number];
  309. [muText insertString:@" " atIndex:range.location +plus*2];
  310. [muText insertString:@" " atIndex:(range.location + range.length+1+plus*2)];
  311. //保存空格位置,以后删除
  312. [numberArr addObject:[NSNumber numberWithInteger:range.location]];
  313. [numberArr addObject:[NSNumber numberWithInteger:(range.location + range.length)]];
  314. plus++;
  315. }
  316. }
  317. text = muText;
  318. NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypePhoneNumber|NSTextCheckingTypeLink error:&error];
  319. self.matches = [detector matchesInString:text options:0 range:NSMakeRange(0, text.length)];
  320. [self highlightLinksWithIndex:NSNotFound];
  321. //删除之前添加的空格
  322. for (int i = 0; i < [numberArr count]; i++) {
  323. NSNumber * index = numberArr[i];
  324. [muText deleteCharactersInRange:NSMakeRange([index integerValue], 1)];
  325. }
  326. text = muText;
  327. }
  328. - (NSArray *)setTextWithAttribute:(NSString *)text attributedText:(NSMutableAttributedString *)attributedText regulaStr:(NSString *)regulaStr {
  329. NSError *error;
  330. //可以识别url的正则表达式
  331. // 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\\.\\-~!@#$%^&*+?:_/=<>]*)?)";
  332. NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regulaStr
  333. options:NSRegularExpressionDotMatchesLineSeparators|NSRegularExpressionCaseInsensitive
  334. error:&error];
  335. NSArray *arrayOfAllMatches = [regex matchesInString:text options:0 range:NSMakeRange(0, [text length])];
  336. if (!arrayOfAllMatches || arrayOfAllMatches.count <= 0) {
  337. return nil;
  338. }
  339. NSMutableArray *arr=[[NSMutableArray alloc]init];
  340. NSMutableArray *rangeArr=[[NSMutableArray alloc]init];
  341. for (NSTextCheckingResult *match in arrayOfAllMatches)
  342. {
  343. NSString* substringForMatch;
  344. substringForMatch = [text substringWithRange:match.range];
  345. [arr addObject:substringForMatch];
  346. }
  347. NSString *subStr=[text copy];
  348. NSUInteger index = 0;
  349. for (NSString *str in arr) {
  350. NSValue *value = [self rangesOfString:str inString:subStr];
  351. NSRange range = [value rangeValue];
  352. if ((range.location + range.length) < text.length) {
  353. subStr = [subStr substringFromIndex:range.location + range.length];
  354. }
  355. range.location += index;
  356. value = [NSValue valueWithRange:range];
  357. [rangeArr addObject:value];
  358. index = range.location + range.length;
  359. }
  360. // UIFont *font = self.font;
  361. // NSMutableAttributedString *attributedText;
  362. // attributedText=[[NSMutableAttributedString alloc]initWithString:subStr attributes:@{NSFontAttributeName :font}];
  363. self.matches = [NSMutableArray array];
  364. for(NSValue *value in rangeArr)
  365. {
  366. NSInteger index=[rangeArr indexOfObject:value];
  367. NSRange range=[value rangeValue];
  368. NSDataDetector *detector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypePhoneNumber|NSTextCheckingTypeLink error:&error];
  369. [self.matches addObjectsFromArray:[detector matchesInString:text options:0 range:range]];
  370. NSString * urlStr = [[arr objectAtIndex:index] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
  371. [attributedText addAttribute:NSLinkAttributeName value:[NSURL URLWithString:urlStr] range:range];
  372. [attributedText addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:range];
  373. }
  374. // self.attributedText = attributedText;
  375. return rangeArr;
  376. }
  377. //获取查找字符串在母串中的NSRange
  378. - (NSValue *)rangesOfString:(NSString *)searchString inString:(NSString *)str {
  379. NSRange searchRange = NSMakeRange(0, [str length]);
  380. NSRange range;
  381. if ((range = [str rangeOfString:searchString options:0 range:searchRange]).location != NSNotFound) {
  382. searchRange = NSMakeRange(NSMaxRange(range), [str length] - NSMaxRange(range));
  383. }
  384. return [NSValue valueWithRange:range];
  385. }
  386. - (BOOL)isIndex:(CFIndex)index inRange:(NSRange)range {
  387. return index > range.location && index <= range.location+range.length;
  388. }
  389. - (void)highlightLinksWithIndex:(CFIndex)index {
  390. if(self.contentEmoji){
  391. return;
  392. }
  393. NSMutableAttributedString* attributedString = [self.attributedText mutableCopy];
  394. //因为之前添加空格位置发生变化
  395. int plus = 0;
  396. for (NSTextCheckingResult *match in self.matches) {
  397. if ([match resultType] == NSTextCheckingTypePhoneNumber||[match resultType] == NSTextCheckingTypeLink) {
  398. NSRange matchRange;
  399. if ([match resultType] == NSTextCheckingTypePhoneNumber) {
  400. matchRange = NSMakeRange(match.range.location -1 -2*plus, match.range.length);
  401. plus++;
  402. }else{
  403. matchRange = NSMakeRange(match.range.location -2*plus, match.range.length);
  404. }
  405. if (matchRange.location == 18446744073709551615 &&matchRange.length !=0) {
  406. matchRange.location =0;
  407. }
  408. //被点击时吗,判断index在range蓝色字体范围内,则变灰,默认为蓝色
  409. if ((matchRange.location + matchRange.length) > attributedString.length) {
  410. matchRange.length = attributedString.length - matchRange.location;
  411. }
  412. if (matchRange.length <= attributedString.length) {
  413. if ([self isIndex:index inRange:matchRange]) {
  414. [attributedString addAttribute:NSForegroundColorAttributeName value:[UIColor grayColor] range:matchRange];
  415. }
  416. else {
  417. [attributedString addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:matchRange];
  418. }
  419. //添加下划线
  420. if ([match resultType] == NSTextCheckingTypeLink) {
  421. [attributedString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:matchRange];
  422. }
  423. }
  424. }
  425. }
  426. self.attributedText = attributedString;
  427. }
  428. //被点击时获取特殊字符的位置
  429. - (CFIndex)characterIndexAtPoint:(CGPoint)point {
  430. ////////
  431. NSMutableAttributedString* optimizedAttributedText = [self.attributedText mutableCopy];
  432. // use label's font and lineBreakMode properties in case the attributedText does not contain such attributes
  433. [self.attributedText enumerateAttributesInRange:NSMakeRange(0, [self.attributedText length]) options:0 usingBlock:^(NSDictionary *attrs, NSRange range, BOOL *stop) {
  434. if (!attrs[(NSString*)kCTFontAttributeName]) {
  435. [optimizedAttributedText addAttribute:(NSString*)kCTFontAttributeName value:self.font range:NSMakeRange(0, [self.attributedText length])];
  436. }
  437. if (!attrs[(NSString*)kCTParagraphStyleAttributeName]) {
  438. NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
  439. [paragraphStyle setLineBreakMode:self.lineBreakMode];
  440. [optimizedAttributedText addAttribute:(NSString*)kCTParagraphStyleAttributeName value:paragraphStyle range:range];
  441. }
  442. }];
  443. // modify kCTLineBreakByTruncatingTail lineBreakMode to kCTLineBreakByWordWrapping
  444. [optimizedAttributedText enumerateAttribute:(NSString*)kCTParagraphStyleAttributeName inRange:NSMakeRange(0, [optimizedAttributedText length]) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) {
  445. NSMutableParagraphStyle* paragraphStyle = [value mutableCopy];
  446. if ([paragraphStyle lineBreakMode] == kCTLineBreakByTruncatingTail) {
  447. [paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];
  448. }
  449. [optimizedAttributedText removeAttribute:(NSString*)kCTParagraphStyleAttributeName range:range];
  450. [optimizedAttributedText addAttribute:(NSString*)kCTParagraphStyleAttributeName value:paragraphStyle range:range];
  451. }];
  452. ////////
  453. if (!CGRectContainsPoint(self.bounds, point)) {
  454. return NSNotFound;
  455. }
  456. CGRect textRect = [self textRect];
  457. if (!CGRectContainsPoint(textRect, point)) {
  458. return NSNotFound;
  459. }
  460. // Offset tap coordinates by textRect origin to make them relative to the origin of frame
  461. point = CGPointMake(point.x - textRect.origin.x, point.y - textRect.origin.y);
  462. // Convert tap coordinates (start at top left) to CT coordinates (start at bottom left)
  463. point = CGPointMake(point.x, textRect.size.height - point.y);
  464. //////
  465. CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)optimizedAttributedText);
  466. CGMutablePathRef path = CGPathCreateMutable();
  467. CGPathAddRect(path, NULL, textRect);
  468. CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, [self.attributedText length]), path, NULL);
  469. if (frame == NULL) {
  470. CFRelease(path);
  471. return NSNotFound;
  472. }
  473. CFArrayRef lines = CTFrameGetLines(frame);
  474. NSInteger numberOfLines = self.numberOfLines > 0 ? MIN(self.numberOfLines, CFArrayGetCount(lines)) : CFArrayGetCount(lines);
  475. //NSLog(@"num lines: %d", numberOfLines);
  476. if (numberOfLines == 0) {
  477. CFRelease(frame);
  478. CFRelease(path);
  479. return NSNotFound;
  480. }
  481. NSUInteger idx = NSNotFound;
  482. CGPoint lineOrigins[numberOfLines];
  483. CTFrameGetLineOrigins(frame, CFRangeMake(0, numberOfLines), lineOrigins);
  484. for (CFIndex lineIndex = 0; lineIndex < numberOfLines; lineIndex++) {
  485. CGPoint lineOrigin = lineOrigins[lineIndex];
  486. CTLineRef line = CFArrayGetValueAtIndex(lines, lineIndex);
  487. // Get bounding information of line
  488. CGFloat ascent, descent, leading, width;
  489. width = CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
  490. CGFloat yMin = floor(lineOrigin.y - descent);
  491. CGFloat yMax = ceil(lineOrigin.y + ascent);
  492. // Check if we've already passed the line
  493. if (point.y > yMax) {
  494. break;
  495. }
  496. // Check if the point is within this line vertically
  497. if (point.y >= yMin) {
  498. // Check if the point is within this line horizontally
  499. if (point.x >= lineOrigin.x && point.x <= lineOrigin.x + textRect.size.width) {
  500. // Convert CT coordinates to line-relative coordinates
  501. CGPoint relativePoint = CGPointMake(point.x - lineOrigin.x, point.y - lineOrigin.y);
  502. idx = CTLineGetStringIndexForPosition(line, relativePoint);
  503. break;
  504. }
  505. }
  506. }
  507. CFRelease(frame);
  508. CFRelease(path);
  509. return idx;
  510. }
  511. //上面的方法调用
  512. - (CGRect)textRect {
  513. CGRect textRect = [self textRectForBounds:self.bounds limitedToNumberOfLines:self.numberOfLines];
  514. textRect.origin.y = (self.bounds.size.height - textRect.size.height)/2;
  515. if (self.textAlignment == NSTextAlignmentCenter) {
  516. textRect.origin.x = (self.bounds.size.width - textRect.size.width)/2;
  517. }
  518. if (self.textAlignment == NSTextAlignmentRight) {
  519. textRect.origin.x = self.bounds.size.width - textRect.size.width;
  520. }
  521. return textRect;
  522. }
  523. - (void)setText:(NSString *)text {
  524. int faceIndex = 0;
  525. [data removeAllObjects];
  526. [self getImageRange:text array:data];
  527. NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] init];
  528. for (int i=0;i<[data count];i++) {
  529. NSString *str=[data objectAtIndex:i];
  530. BOOL isFace = NO;
  531. NSInteger n;
  532. if ([str hasPrefix:BEGIN_FLAG]&&[str hasSuffix:END_FLAG]) {
  533. isFace = [shortNameArrayC indexOfObject:str] != NSNotFound;
  534. n = [shortNameArrayC indexOfObject:str];
  535. if (!isFace) {
  536. isFace = [shortNameArrayE indexOfObject:str] != NSNotFound;
  537. n = [shortNameArrayE indexOfObject:str];
  538. }
  539. if(isFace){
  540. NSDictionary *dic = [g_constant.emojiArray objectAtIndex:n];
  541. // 创建图片图片附件
  542. NSTextAttachment *attach = [[NSTextAttachment alloc] init];
  543. attach.image = [UIImage imageNamed:dic[@"filename"]];
  544. attach.bounds = CGRectMake(0, 0, faceWidth, faceHeight);
  545. NSAttributedString *attachString = [NSAttributedString attributedStringWithAttachment:attach];
  546. //将图片插入到合适的位置
  547. [attStr insertAttributedString:attachString atIndex:faceIndex];
  548. faceIndex ++;
  549. }
  550. }
  551. //不是表情
  552. if(!isFace) {
  553. if (str.length > 0) {
  554. // 防止出现特殊符号自动换行问题
  555. NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
  556. paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;
  557. NSAttributedString *att = [[NSAttributedString alloc] initWithString:str attributes:@{NSFontAttributeName : self.font,NSParagraphStyleAttributeName:paragraphStyle}];
  558. [attStr insertAttributedString:att atIndex:faceIndex];
  559. NSMutableString *string = [str mutableCopy];
  560. for (NSInteger i = 0; i < faceIndex; i ++) {
  561. [string insertString:@" " atIndex:0];
  562. }
  563. // NSString *regulaStr = @"((http[s]{0,1}|ftp)://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z0-9]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)|(www.[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)";
  564. // NSString *regulaStr = @"^((https?|ftp|file)://)?[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]";
  565. // NSString *regulaStr = @"(((ht|f)tp(s?))\://)?(www.|[a-zA-Z0-9].)[a-zA-Z0-9\-\.]+\.(com|edu|gov|mil|net|org|biz|info|name|museum|us|ca|uk)(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\;\?\'\\\+&%\$#\=~_\-]+))*";
  566. // regulaStr = @"((((ht|f)tp(s?))\\://)([a-zA-Z0-9\\-]+)(.[a-zA-Z0-9\\-]+)+|([a-zA-Z0-9\\-]+.)+(com|edu|gov|mil|net|org|biz|info|name|museum|us|ca|uk))(\\:[0-9]+)*(/($|[a-zA-Z0-9\\.\\,\\;\?\'\\\\+&%\\$#\\=~_\\-]+))*";
  567. NSString *regulaStr = @"((http[s]{0,1}|ftp)://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z0-9]+)(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)|(([a-zA-Z0-9\\-]+\\.)+(com|cn|cc|top|xyz|edu|gov|mil|net|org|biz|info|name|museum|us|ca|uk)(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)";
  568. // 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\\.\\-~!@#$%^&*+?:_/=<>]*)?)";
  569. [self setTextWithAttribute:string attributedText:attStr regulaStr:regulaStr];
  570. regulaStr = @"((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$";
  571. [self setTextWithAttribute:string attributedText:attStr regulaStr:regulaStr];
  572. }
  573. faceIndex += str.length;
  574. }
  575. }
  576. self.attributedText = attStr;
  577. CGSize size1 = [self sizeThatFits:CGSizeMake(maxWidth, MAXFLOAT)];
  578. self.frame = CGRectMake(self.frame.origin.x,self.frame.origin.y, size1.width, size1.height);
  579. }
  580. /*
  581. -(void) setText:(NSString *)text{
  582. [super setText:text];
  583. [data removeAllObjects];
  584. [self getImageRange:text array:data];
  585. _size = self.font.pointSize;
  586. // maxWidth = self.frame.size.width+offset;
  587. // maxWidth = self.frame.size.width-_size*0.5;
  588. NSString *firstStr = data.firstObject;
  589. NSString *tempStr = [firstStr substringWithRange:NSMakeRange(0, 1)];
  590. CGSize size =[tempStr boundingRectWithSize:CGSizeMake(_size, _size) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:self.font} context:nil].size;
  591. CGFloat upX = 0;
  592. CGFloat upY = size.height;
  593. CGFloat height = 0;
  594. BOOL isMoreLine=NO;
  595. if (data) {
  596. for (int i=0;i<[data count];i++) {
  597. NSString *str=[data objectAtIndex:i];
  598. BOOL isFace = NO;
  599. //是表情
  600. if ([str hasPrefix:BEGIN_FLAG]&&[str hasSuffix:END_FLAG]) {
  601. isFace = [shortNameArrayC indexOfObject:str] != NSNotFound;
  602. if (!isFace) {
  603. isFace = [shortNameArrayE indexOfObject:str] != NSNotFound;
  604. }
  605. if(isFace){
  606. if ((upX + faceWidth) >= maxWidth)
  607. {
  608. upY = upY + height;
  609. upX = 0;
  610. isMoreLine = YES;
  611. height = 0;
  612. }
  613. upX=faceWidth+upX;
  614. height = faceHeight;
  615. if (!isMoreLine) {
  616. upY = height;
  617. }
  618. }
  619. }
  620. //不是表情
  621. if(!isFace) {
  622. for (int j = 0; j < [str length]; j++) {
  623. NSString *temp = [str substringWithRange:NSMakeRange(j, 1)];
  624. CGSize size =[temp boundingRectWithSize:CGSizeMake(_size, _size) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:self.font} context:nil].size;
  625. if([temp isEqualToString:@"\n"] || [temp isEqualToString:@"\r"]){
  626. upY = upY + 20;
  627. upX = 0;
  628. isMoreLine = YES;
  629. }else{
  630. // CGSize size=[temp sizeWithFont:self.font constrainedToSize:CGSizeMake(_size, _size)];
  631. if ((upX + size.width) >= maxWidth)
  632. {
  633. upY = upY + size.height;
  634. upX = 0;
  635. isMoreLine = YES;
  636. height = 0;
  637. }
  638. upX=upX+size.width;
  639. if (height != faceHeight) {
  640. height = size.height;
  641. }
  642. if (!isMoreLine) {
  643. upY = height;
  644. }
  645. }
  646. }
  647. }
  648. }
  649. }
  650. if(upY<self.frame.size.height){
  651. // _top = (self.frame.size.height-upY)/2;
  652. // NSLog(@"_top=%d/%d",_top,self.frame.size.height);
  653. }
  654. if(upY<_size)
  655. upY = _size;
  656. // if(upY<self.frame.size.height)
  657. // upY = self.frame.size.height;
  658. if(isMoreLine){
  659. CGSize moreSize = [text boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:self.font} context:nil].size;
  660. if (moreSize.width > maxWidth) {
  661. upX = maxWidth;
  662. }else {
  663. upX = moreSize.width;
  664. }
  665. }
  666. else
  667. upX = upX;
  668. self.frame = CGRectMake(self.frame.origin.x,self.frame.origin.y, upX, upY + 3); //@ 需要将该view的尺寸记下,方便以后使用
  669. // NSLog(@"%d,%.1f %.1f", [data count], upX, upY);
  670. if (!self.contentEmoji) {
  671. if (text == nil) {
  672. return;
  673. }
  674. // if (self.isShowNumber) {
  675. [self setAttributedTextRange:text];
  676. // }
  677. // 显示链接
  678. // [self setTextWithLinkAttribute:text];
  679. }
  680. }
  681. */
  682. #pragma mark ---------------点击事件----------------
  683. - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
  684. self.lastTouches = touches;
  685. UITouch *touch = [touches anyObject];
  686. CFIndex index = [self characterIndexAtPoint:[touch locationInView:self]];
  687. if (![self label:self didBeginTouch:touch onCharacterAtIndex:index]) {
  688. [super touchesBegan:touches withEvent:event];
  689. }
  690. }
  691. - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
  692. // self.lastTouches = touches;
  693. UITouch *touch = [touches anyObject];
  694. CFIndex index = [self characterIndexAtPoint:[touch locationInView:self]];
  695. if (![self label:self didMoveTouch:touch onCharacterAtIndex:index]) {
  696. [super touchesMoved:touches withEvent:event];
  697. }
  698. }
  699. - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
  700. if (!self.lastTouches) {
  701. return;
  702. }
  703. self.lastTouches = nil;
  704. UITouch *touch = [touches anyObject];
  705. CFIndex index = [self characterIndexAtPoint:[touch locationInView:self]];
  706. if (![self label:self didEndTouch:touch onCharacterAtIndex:index]) {
  707. [super touchesEnded:touches withEvent:event];
  708. }
  709. }
  710. - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
  711. if (!self.lastTouches) {
  712. return;
  713. }
  714. self.lastTouches = nil;
  715. UITouch *touch = [touches anyObject];
  716. if (![self label:self didCancelTouch:touch]) {
  717. [super touchesCancelled:touches withEvent:event];
  718. }
  719. }
  720. - (void)cancelCurrentTouch {
  721. if (self.lastTouches) {
  722. [self label:self didCancelTouch:[self.lastTouches anyObject]];
  723. self.lastTouches = nil;
  724. }
  725. }
  726. #pragma mark -------------点击处理------------------
  727. - (BOOL)label:(JXEmoji *)label didBeginTouch:(UITouch *)touch onCharacterAtIndex:(CFIndex)charIndex {
  728. [self highlightLinksWithIndex:charIndex];
  729. return YES;
  730. }
  731. - (BOOL)label:(JXEmoji *)label didMoveTouch:(UITouch *)touch onCharacterAtIndex:(CFIndex)charIndex {
  732. [self highlightLinksWithIndex:charIndex];
  733. return YES;
  734. }
  735. //这里对文本的电话号码处理
  736. - (BOOL)label:(JXEmoji *)label didEndTouch:(UITouch *)touch onCharacterAtIndex:(CFIndex)charIndex {
  737. [g_window endEditing:YES];
  738. [self highlightLinksWithIndex:NSNotFound];
  739. int plus = 0;
  740. for (NSTextCheckingResult *match in self.matches) {
  741. if ([match resultType] == NSTextCheckingTypePhoneNumber) {
  742. NSRange matchRange = NSMakeRange(match.range.location -1 -2*plus, match.range.length);
  743. if (matchRange.location == 18446744073709551615 &&matchRange.length !=0) {
  744. matchRange.location =0;
  745. }
  746. self.textCopy = match.phoneNumber;
  747. if ([self isIndex:charIndex inRange:matchRange]) {
  748. self.actionVC = [[JXActionSheetVC alloc] initWithImages:@[] names:@[Localized(@"JX_Copy"),Localized(@"JXEmoji_CallPhone")]];
  749. self.actionVC.delegate = self;
  750. self.actionVC.tag = 1;
  751. [g_App.window addSubview:self.actionVC.view];
  752. break;
  753. }
  754. plus++;
  755. }else if ([match resultType] == NSTextCheckingTypeLink){
  756. NSRange matchRange = NSMakeRange(match.range.location -2*plus, match.range.length);
  757. self.textCopy = [NSString stringWithFormat:@"%@",match.URL];
  758. if ([self isIndex:charIndex inRange:matchRange]) {
  759. // self.actionVC = [[JXActionSheetVC alloc] initWithImages:@[] names:@[Localized(@"JX_Copy"),Localized(@"JXEmoji_OpenUrl")]];
  760. // self.actionVC.delegate = self;
  761. // self.actionVC.tag = 2;
  762. // [g_App.window addSubview:self.actionVC.view];
  763. // dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  764. // [g_window endEditing:YES];
  765. webpageVC *webVC = [webpageVC alloc];
  766. webVC.isGotoBack= YES;
  767. webVC.isSend = YES;
  768. webVC.url = self.textCopy;
  769. webVC = [webVC init];
  770. [g_navigation.navigationView addSubview:webVC.view];
  771. // [g_navigation pushViewController:webVC animated:YES];
  772. // NSURL *cleanURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@", self.textCopy]];
  773. // [[UIApplication sharedApplication] openURL:cleanURL];
  774. // });
  775. break;
  776. }
  777. }
  778. }
  779. return YES;
  780. }
  781. #pragma -mark actionSheet回调方法
  782. - (void)actionSheet:(JXActionSheetVC *)actionSheet didButtonWithIndex:(NSInteger)index {
  783. self.backgroundColor=[UIColor clearColor];
  784. if (actionSheet.tag==1) {
  785. //复制
  786. if(index==0){
  787. UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
  788. [pasteboard setString:self.textCopy];
  789. }else if(index==1){//打电话
  790. [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"tel://%@",self.textCopy]]];
  791. }
  792. }else if (actionSheet.tag==2){
  793. //打开网址
  794. if(index==1){
  795. // [[UIApplication sharedApplication] openURL:[NSURL URLWithString:self.textCopy]];
  796. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  797. // [g_window endEditing:YES];
  798. webpageVC *webVC = [webpageVC alloc];
  799. webVC.isGotoBack= YES;
  800. webVC.isSend = YES;
  801. webVC.url = self.textCopy;
  802. webVC = [webVC init];
  803. [g_navigation.navigationView addSubview:webVC.view];
  804. // [g_navigation pushViewController:webVC animated:YES];
  805. // NSURL *cleanURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@", self.textCopy]];
  806. // [[UIApplication sharedApplication] openURL:cleanURL];
  807. });
  808. [actionSheet.view removeFromSuperview];
  809. }else if(index==0){//复制
  810. UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
  811. [pasteboard setString:self.textCopy];
  812. }
  813. }
  814. }
  815. - (BOOL)label:(JXEmoji *)label didCancelTouch:(UITouch *)touch {
  816. [self highlightLinksWithIndex:NSNotFound];
  817. }
  818. @end