HTMLAnalysisHelper.m 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. //
  2. // HTMLAnalysisHelper.m
  3. // HTMLAnalysisDemo
  4. //
  5. // Created by ztcj_develop_mini on 2019/3/25.
  6. // Copyright © 2019 ztcj_develop_mini. All rights reserved.
  7. //
  8. #import "HTMLAnalysisHelper.h"
  9. #import "AttributedStrModel.h"
  10. #import "YYText.h"
  11. #import <TFHpple/TFHpple.h>
  12. #import <UIImageView+WebCache.h>
  13. @interface HTMLAnalysisHelper ()
  14. @property (nonatomic, strong)NSMutableArray *attributeStrArr;
  15. @property (nonatomic, strong)NSMutableArray *imgUrlStrArr; //html中所嵌的图片url 数组
  16. @end
  17. @implementation HTMLAnalysisHelper
  18. - (instancetype)init
  19. {
  20. if (self = [super init]) {
  21. self.fontSize = kDefaultFontSize;
  22. self.imageWidth = kDefaultImgWidth;
  23. self.textLineSpacing = kDefaultTextLineSpacing;
  24. self.paragraphSpacing = kDefaultParagraphSpacing;
  25. }
  26. return self;
  27. }
  28. - (void)setFontSize:(CGFloat)fontSize
  29. {
  30. _fontSize = fontSize;
  31. [self getAttributeStrWithOpenState:YES];
  32. [self getAttributeStrWithOpenState:NO];
  33. }
  34. - (void)setImageWidth:(CGFloat)imageWidth
  35. {
  36. _imageWidth = imageWidth;
  37. [self getAttributeStrWithOpenState:YES];
  38. [self getAttributeStrWithOpenState:NO];
  39. }
  40. - (void)setTextLineSpacing:(CGFloat)textLineSpacing
  41. {
  42. _textLineSpacing = textLineSpacing;
  43. [self getAttributeStrWithOpenState:YES];
  44. [self getAttributeStrWithOpenState:NO];
  45. }
  46. - (void)setParagraphSpacing:(CGFloat)paragraphSpacing
  47. {
  48. _paragraphSpacing = paragraphSpacing;
  49. [self getAttributeStrWithOpenState:YES];
  50. [self getAttributeStrWithOpenState:NO];
  51. }
  52. #pragma mark -- 解析字符串,放到一个数组里
  53. - (void)analysisWithHTMLStr:(NSString *)htmlStr{
  54. dispatch_async(dispatch_get_main_queue(), ^{
  55. [self.attributeStrArr removeAllObjects];
  56. //先转成富文本
  57. NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc]initWithData:[htmlStr dataUsingEncoding:NSUnicodeStringEncoding] options:@{NSDocumentTypeDocumentAttribute:NSHTMLTextDocumentType} documentAttributes:nil error:nil];
  58. //枚举取出所有富文本,放到一个AttributedStrModel数组里
  59. __weak typeof(self) wself = self;
  60. [attributeString enumerateAttributesInRange:NSMakeRange(0, attributeString.length) options:0 usingBlock:^(NSDictionary<NSAttributedStringKey,id> * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) {
  61. // NSLog(@"%@",attrs);
  62. //创建模型装载数据对象
  63. AttributedStrModel *attributeStrModel = [[AttributedStrModel alloc]init];
  64. NSTextAttachment *attachment = [attrs objectForKey:NSAttachmentAttributeName];
  65. if (attachment) { //图片
  66. attributeStrModel.type = ImageAttributedStrType;
  67. // attachment.fileWrapper.preferredFilename 拿到的是URL路径最后面的图片名称
  68. attributeStrModel.imgName = [attachment.fileWrapper.preferredFilename componentsSeparatedByString:@"."].firstObject;
  69. }
  70. else{ // 文本
  71. attributeStrModel.type = TextAttributedStrType;
  72. //调整字体大小为我们想要的大小
  73. attributeStrModel.attributeStr = [[NSMutableAttributedString alloc]initWithAttributedString:[attributeString attributedSubstringFromRange:range]];
  74. UIFont *font = [attrs objectForKey:NSFontAttributeName];
  75. if (!font) {
  76. font = [UIFont systemFontOfSize:self.fontSize];
  77. }
  78. else{
  79. font = [UIFont fontWithName:font.fontName size:self.fontSize];
  80. }
  81. attributeStrModel.attributeStr.yy_font = font;
  82. attributeStrModel.attributeStr.yy_color = LZA3AABEColor;
  83. //去掉超链接的下划线
  84. NSURL *link = [attrs objectForKey:NSLinkAttributeName];
  85. if (link) {
  86. attributeStrModel.attributeStr.yy_underlineStyle = NSUnderlineStyleNone;
  87. }
  88. }
  89. [wself.attributeStrArr addObject:attributeStrModel];
  90. }];
  91. [self getAttributeStrWithOpenState:YES];
  92. [self getAttributeStrWithOpenState:NO];
  93. [self getImgUrlArrWithHTMLStr:htmlStr];
  94. });
  95. }
  96. #pragma mark -- 获取所有的图片URL并加载
  97. - (void)getImgUrlArrWithHTMLStr:(NSString *)htmlStr
  98. {
  99. [self.imgUrlStrArr removeAllObjects];
  100. NSData *data = [htmlStr dataUsingEncoding:NSUTF8StringEncoding];
  101. TFHpple *xpathParser = [[TFHpple alloc]initWithHTMLData:data];
  102. // 获取所有的图片链接
  103. NSArray *elements = [xpathParser searchWithXPathQuery:@"//img"];
  104. for (TFHppleElement *element in elements) {
  105. if (element.attributes[@"src"]) {
  106. [self.imgUrlStrArr addObject:element.attributes[@"src"]];
  107. }
  108. }
  109. //加载图片
  110. __weak typeof(self) wself = self;
  111. for (NSString *imgUrlStr in self.imgUrlStrArr) {
  112. //取出URL路径最后面的图片名称
  113. NSString *imgName = [[[imgUrlStr componentsSeparatedByString:@"?"] firstObject] lastPathComponent];
  114. imgName = [imgName componentsSeparatedByString:@"."].firstObject;
  115. NSURL *imgUrl = [NSURL URLWithString:imgUrlStr];
  116. SDWebImageManager *manager = [SDWebImageManager sharedManager] ;
  117. [manager loadImageWithURL:imgUrl options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
  118. } completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
  119. if (image) {
  120. for (AttributedStrModel *strModel in wself.attributeStrArr) {
  121. if (strModel.type == ImageAttributedStrType) {
  122. //比对图片名称是否一致
  123. if ([strModel.imgName isEqualToString:imgName]) {
  124. strModel.image = image;
  125. [wself getAttributeStrWithOpenState:YES];
  126. break;
  127. }
  128. }
  129. }
  130. }
  131. }];
  132. }
  133. }
  134. #pragma mark -- 获取展开和关闭的富文本内容
  135. - (void)getAttributeStrWithOpenState:(BOOL)isOpen
  136. {
  137. if (!self.attributeStrArr.count) {
  138. return;
  139. }
  140. //拼接要显示的字符串
  141. NSMutableAttributedString *attributeStrM = [[NSMutableAttributedString alloc]init];
  142. for (AttributedStrModel *strModel in self.attributeStrArr) {
  143. //收起状态下只拼接文本
  144. if (strModel.type == TextAttributedStrType) {
  145. [attributeStrM appendAttributedString:strModel.attributeStr];
  146. }
  147. //展开状态下且图片已加载完成则拼接上图片
  148. else if (strModel.type == ImageAttributedStrType && strModel.image && isOpen){
  149. //等比缩放
  150. CGFloat imageW = self.imageWidth;
  151. CGFloat imageH = self.imageWidth / strModel.image.size.width * strModel.image.size.height;
  152. NSMutableAttributedString *attachText = [NSMutableAttributedString yy_attachmentStringWithContent:strModel.image contentMode:UIViewContentModeScaleAspectFill attachmentSize:CGSizeMake(imageW, imageH) alignToFont:[UIFont systemFontOfSize:self.fontSize] alignment:YYTextVerticalAlignmentCenter];
  153. [attributeStrM appendAttributedString:attachText];
  154. }
  155. }
  156. attributeStrM.yy_lineSpacing = self.textLineSpacing;
  157. attributeStrM.yy_paragraphSpacing = self.paragraphSpacing;
  158. //添加点击 所有内容 实现展开关闭事件
  159. __weak typeof(self) wself = self;
  160. [attributeStrM yy_setTextHighlightRange:NSMakeRange(0, attributeStrM.length) color:[UIColor blackColor] backgroundColor:nil tapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) {
  161. if (wself.openCloseBlock) {
  162. wself.openCloseBlock();
  163. }
  164. }];
  165. //添加点击 超链接 & 点击图片 的回调
  166. [attributeStrM enumerateAttributesInRange:NSMakeRange(0, attributeStrM.length) options:0 usingBlock:^(NSDictionary<NSAttributedStringKey,id> * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) {
  167. NSURL *link = [attrs objectForKey:NSLinkAttributeName];
  168. //有超链接
  169. if (link) {
  170. attributeStrM.yy_color = [UIColor whiteColor];
  171. [attributeStrM yy_setTextHighlightRange:range color:DecColorFromRGB(204,168,90) backgroundColor:nil tapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) {
  172. if (wself.linkClickedBlock) {
  173. wself.linkClickedBlock(link.absoluteString);
  174. }
  175. }];
  176. }else{
  177. attributeStrM.yy_color = LZA3AABEColor;
  178. }
  179. YYTextAttachment *attachment = [attrs objectForKey:YYTextAttachmentAttributeName];
  180. //图片不为空
  181. if (attachment) {
  182. [attributeStrM yy_setTextHighlightRange:range color:nil backgroundColor:nil tapAction:^(UIView * _Nonnull containerView, NSAttributedString * _Nonnull text, NSRange range, CGRect rect) {
  183. if (wself.imageClickedBlock) {
  184. wself.imageClickedBlock(attachment.content);
  185. }
  186. }];
  187. }
  188. }];
  189. if (isOpen) {
  190. self.openStr = attributeStrM;
  191. }
  192. else{
  193. self.closeStr = attributeStrM;
  194. }
  195. }
  196. #pragma mark -- LazyLoad
  197. - (NSMutableArray *)attributeStrArr
  198. {
  199. if (!_attributeStrArr) {
  200. _attributeStrArr = [[NSMutableArray alloc]init];
  201. }
  202. return _attributeStrArr;
  203. }
  204. - (NSMutableArray *)imgUrlStrArr
  205. {
  206. if (!_imgUrlStrArr) {
  207. _imgUrlStrArr = [[NSMutableArray alloc]init];
  208. }
  209. return _imgUrlStrArr;
  210. }
  211. @end