线上所有马甲包模板,与《猎豆》同UI。域名zhuadd

MLExpressionManager.m 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. //
  2. // MLExpressionManager.m
  3. // Pods
  4. //
  5. // Created by molon on 15/6/18.
  6. //
  7. //
  8. #import "MLExpressionManager.h"
  9. #import "MLTextAttachment.h"
  10. /*
  11. 如果设置高于1.00f的话,会引起 有表情行的行距 显得比 没表情行的行距 多,显得不工整
  12. https://github.com/molon/MLLabel/issues/1
  13. 所以我们还是设置为1.00f,至于怎么解决这个问题,请参考Demo里的ClipExpressionViewController
  14. */
  15. #define kExpressionLineHeightMultiple 1.00f
  16. @interface MLExpression()
  17. @property (nonatomic, copy) NSString *regex;
  18. @property (nonatomic, copy) NSString *plistName;
  19. @property (nonatomic, copy) NSString *bundleName;
  20. @property (nonatomic, strong) NSRegularExpression *expressionRegularExpression;
  21. @property (nonatomic, strong) NSDictionary *expressionMap;
  22. - (BOOL)isValid;
  23. @end
  24. @interface MLExpressionManager()
  25. @property (nonatomic, strong) NSMutableDictionary *expressionMapRecords;
  26. @property (nonatomic, strong) NSMutableDictionary *expressionRegularExpressionRecords;
  27. @end
  28. @implementation MLExpressionManager
  29. + (instancetype)sharedInstance {
  30. static MLExpressionManager *_sharedInstance = nil;
  31. static dispatch_once_t onceToken;
  32. dispatch_once(&onceToken, ^{
  33. _sharedInstance = [[[self class] alloc]init];
  34. });
  35. return _sharedInstance;
  36. }
  37. #pragma mark - getter
  38. - (NSMutableDictionary *)expressionMapRecords
  39. {
  40. if (!_expressionMapRecords) {
  41. _expressionMapRecords = [NSMutableDictionary new];
  42. }
  43. return _expressionMapRecords;
  44. }
  45. - (NSMutableDictionary *)expressionRegularExpressionRecords
  46. {
  47. if (!_expressionRegularExpressionRecords) {
  48. _expressionRegularExpressionRecords = [NSMutableDictionary new];
  49. }
  50. return _expressionRegularExpressionRecords;
  51. }
  52. #pragma mark - common
  53. - (NSDictionary*)expressionMapWithPlistName:(NSString*)plistName
  54. {
  55. NSAssert(plistName&&plistName.length>0, @"expressionMapWithRegex:参数不得为空");
  56. if (self.expressionMapRecords[plistName]) {
  57. return self.expressionMapRecords[plistName];
  58. }
  59. NSString *plistPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:plistName];
  60. NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
  61. NSAssert(dict,@"表情字典%@找不到,请注意大小写",plistName);
  62. self.expressionMapRecords[plistName] = dict;
  63. return self.expressionMapRecords[plistName];
  64. }
  65. - (NSRegularExpression*)expressionRegularExpressionWithRegex:(NSString*)regex
  66. {
  67. NSAssert(regex&&regex.length>0, @"expressionRegularExpressionWithRegex:参数不得为空");
  68. if (self.expressionRegularExpressionRecords[regex]) {
  69. return self.expressionRegularExpressionRecords[regex];
  70. }
  71. NSRegularExpression *re = [[NSRegularExpression alloc] initWithPattern:regex options:NSRegularExpressionCaseInsensitive error:nil];
  72. NSAssert(re,@"正则%@有误",regex);
  73. self.expressionRegularExpressionRecords[regex] = re;
  74. return self.expressionRegularExpressionRecords[regex];
  75. }
  76. //多线程转表情attrStr
  77. + (NSArray *)expressionAttributedStringsWithStrings:(NSArray*)strings expression:(MLExpression*)expression
  78. {
  79. NSMutableDictionary *results = [NSMutableDictionary dictionaryWithCapacity:strings.count];
  80. dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  81. dispatch_group_t group = dispatch_group_create();
  82. for (id str in strings) {
  83. dispatch_group_async(group, queue, ^{
  84. NSAttributedString *result = [MLExpressionManager expressionAttributedStringWithString:str expression:expression];
  85. @synchronized(results){
  86. results[str] = result;
  87. }
  88. });
  89. }
  90. dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
  91. //重新排列
  92. NSMutableArray *resultArr = [NSMutableArray arrayWithCapacity:results.count];
  93. for (id str in strings) {
  94. [resultArr addObject:results[str]];
  95. }
  96. return resultArr;
  97. }
  98. + (void)expressionAttributedStringsWithStrings:(NSArray*)strings expression:(MLExpression*)expression callback:(void(^)(NSArray *result))callback
  99. {
  100. NSMutableDictionary *results = [NSMutableDictionary dictionaryWithCapacity:strings.count];
  101. dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  102. dispatch_group_t group = dispatch_group_create();
  103. for (id str in strings) {
  104. dispatch_group_async(group, queue, ^{
  105. NSAttributedString *result = [MLExpressionManager expressionAttributedStringWithString:str expression:expression];
  106. @synchronized(results){
  107. results[str] = result;
  108. }
  109. });
  110. }
  111. dispatch_group_notify(group, queue, ^{
  112. //重新排列
  113. NSMutableArray *resultArr = [NSMutableArray arrayWithCapacity:results.count];
  114. for (id str in strings) {
  115. [resultArr addObject:results[str]];
  116. }
  117. dispatch_async(dispatch_get_main_queue(), ^{
  118. if (callback) {
  119. callback(resultArr);
  120. }
  121. });
  122. });
  123. }
  124. + (NSAttributedString*)expressionAttributedStringWithString:(id)string expression:(MLExpression*)expression {
  125. NSAssert(expression&&[expression isValid], @"expression invalid");
  126. NSAssert([string isKindOfClass:[NSString class]]||[string isKindOfClass:[NSAttributedString class]], @"string非字符串. %@",string);
  127. NSAttributedString *attributedString = nil;
  128. if ([string isKindOfClass:[NSString class]]) {
  129. attributedString = [[NSAttributedString alloc]initWithString:string];
  130. }else{
  131. attributedString = string;
  132. }
  133. if (attributedString.length<=0) {
  134. return attributedString;
  135. }
  136. NSMutableAttributedString *resultAttributedString = [NSMutableAttributedString new];
  137. //处理表情
  138. NSArray *results = [expression.expressionRegularExpression matchesInString:attributedString.string
  139. options:NSMatchingWithTransparentBounds
  140. range:NSMakeRange(0, [attributedString length])];
  141. //遍历表情,然后找到对应图像名称,并且处理
  142. NSUInteger location = 0;
  143. for (NSTextCheckingResult *result in results) {
  144. NSRange range = result.range;
  145. NSAttributedString *subAttrStr = [attributedString attributedSubstringFromRange:NSMakeRange(location, range.location - location)];
  146. //先把非表情的部分加上去
  147. [resultAttributedString appendAttributedString:subAttrStr];
  148. //下次循环从表情的下一个位置开始
  149. location = NSMaxRange(range);
  150. NSAttributedString *expressionAttrStr = [attributedString attributedSubstringFromRange:range];
  151. NSString *imageName = expression.expressionMap[expressionAttrStr.string];
  152. if (imageName.length>0) {
  153. //加个表情到结果中
  154. NSString *imagePath = [expression.bundleName stringByAppendingPathComponent:imageName];
  155. UIImage *image = [UIImage imageNamed:imagePath];
  156. MLTextAttachment *textAttachment = [MLTextAttachment textAttachmentWithLineHeightMultiple:kExpressionLineHeightMultiple imageBlock:^UIImage *(CGRect imageBounds, NSTextContainer *textContainer, NSUInteger charIndex, MLTextAttachment *textAttachment) {
  157. return image;
  158. } imageAspectRatio:image.size.width/image.size.height];
  159. [resultAttributedString appendAttributedString:[NSAttributedString attributedStringWithAttachment:textAttachment]];
  160. }else{
  161. //找不到对应图像名称就直接加上去
  162. [resultAttributedString appendAttributedString:expressionAttrStr];
  163. }
  164. }
  165. if (location < [attributedString length]) {
  166. //到这说明最后面还有非表情字符串
  167. NSRange range = NSMakeRange(location, [attributedString length] - location);
  168. NSAttributedString *subAttrStr = [attributedString attributedSubstringFromRange:range];
  169. [resultAttributedString appendAttributedString:subAttrStr];
  170. }
  171. return resultAttributedString;
  172. }
  173. @end
  174. @implementation MLExpression
  175. - (BOOL)isValid
  176. {
  177. return self.expressionRegularExpression&&self.expressionMap&&self.bundleName.length>0;
  178. }
  179. + (instancetype)expressionWithRegex:(NSString*)regex plistName:(NSString*)plistName bundleName:(NSString*)bundleName
  180. {
  181. MLExpression *expression = [MLExpression new];
  182. expression.regex = regex;
  183. expression.plistName = plistName;
  184. expression.bundleName = bundleName;
  185. NSAssert([expression isValid], @"此expression无效,请检查参数");
  186. return expression;
  187. }
  188. #pragma mark - setter
  189. - (void)setRegex:(NSString *)regex
  190. {
  191. NSAssert(regex.length>0, @"regex length must >0");
  192. _regex = regex;
  193. self.expressionRegularExpression = [[MLExpressionManager sharedInstance]expressionRegularExpressionWithRegex:regex];
  194. }
  195. - (void)setPlistName:(NSString *)plistName
  196. {
  197. NSAssert(plistName.length>0, @"plistName's length must >0");
  198. if (![[plistName lowercaseString] hasSuffix:@".plist"]) {
  199. plistName = [plistName stringByAppendingString:@".plist"];
  200. }
  201. _plistName = plistName;
  202. self.expressionMap = [[MLExpressionManager sharedInstance]expressionMapWithPlistName:plistName];
  203. }
  204. - (void)setBundleName:(NSString *)bundleName
  205. {
  206. if (![[bundleName lowercaseString] hasSuffix:@".bundle"]) {
  207. bundleName = [bundleName stringByAppendingString:@".bundle"];
  208. }
  209. _bundleName = bundleName;
  210. //TODO: 这个最好验证下存在性,后期搞
  211. }
  212. @end