我们在有些时候,因为性能和加载时间的问题,需要用UILabel加载html的方式来代替webview。
大部分情况,UILabel都可以很好的展示出想要的效果,但是却不能满足点击查看大图的需求。
本解决方式思路:获取图片的frame根据点击的point 判断是否属于图片
demo地址
https://github.com/msbaby520/MSHTMLImg
示例html代码
<p>这是第一张图片</p>
<p><img src=\"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1563783041237&di=d0ed16a2df722fce876f82a4d5a45ce1&imgtype=0&src=http%3A%2F%2Fwww.pptbz.com%2Fupfile%2Fpptpic%2F201407%2F2014072815340215.jpg\" width=\"300\" ></p>
<p>这是第二张图片这是第二张图片这是第二张图片这是第二张图片这是第二张图片这是第二张图片这是第二张图片</p>
<p><img src=\"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1563787705041&di=7708747caf3ee9da672ce4ce0848a60c&imgtype=0&src=http%3A%2F%2Fpic41.nipic.com%2F20140508%2F18609517_112216473140_2.jpg\" width=\"300\" ></p>
1、如何展示
NSMutableAttributedString *htmlStr = [[NSMutableAttributedString alloc] initWithData:[str dataUsingEncoding:NSUnicodeStringEncoding] options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType} documentAttributes:nil error:nil];
[htmlStr addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:15] range:NSMakeRange(0, htmlStr.length)];
self.label.attributedText = htmlStr;
效果如下,我们可以通过添加attribute的方式进行其他修饰
通过调试我们会发现
\U0000fffc就是我们的图片占位符
NSAttachment就是我们的图片附件
此时直觉告诉我,获取到图片所在的 range 是至关重要的
2、如何获取图片的range
我们通过查看 NSAttributedString
类,可以发现如下方法,可以帮助我们循环遍历属性字符串得到我们想要的attachment,及其对应的range
[htmlStr enumerateAttributesInRange:NSMakeRange(0, htmlStr.length) options:(NSAttributedStringEnumerationLongestEffectiveRangeNotRequired) usingBlock:^(NSDictionary<NSAttributedStringKey,id> * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) {
if ([attrs objectForKey:NSAttachmentAttributeName]) {
// 获取图片附件所在的range
}
}];
3、如何获取图片的Frame
在属性字符串中我们可以通过range获取frame,代码如下
// 通过图片附件的range获取图片相对于label的Frame
- (CGRect)boundingRectForCharacterRange:(NSRange)range{
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:htmlStr];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
[textStorage addLayoutManager:layoutManager];
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:[self.label bounds].size];
textContainer.lineFragmentPadding = 0;
[layoutManager addTextContainer:textContainer];
NSRange glyphRange;
[layoutManager characterRangeForGlyphRange:range actualGlyphRange:&glyphRange];
CGRect rect = [layoutManager boundingRectForGlyphRange:glyphRange inTextContainer:textContainer];
return rect;
}
4、对第2步进行代码整理
此时通过思考,我们大概知道要进行点击放大图片,需要知道两个条件,一个是image,另一个是frame,那我们就需要借助一个模型来完善代码。
- (void)getImageModelsWithHtmlStr:(NSAttributedString *)htmlStr{
__weak typeof(self) weakSelf = self;
NSMutableArray *arr = [NSMutableArray array];
[htmlStr enumerateAttributesInRange:NSMakeRange(0, htmlStr.length) options:(NSAttributedStringEnumerationLongestEffectiveRangeNotRequired) usingBlock:^(NSDictionary<NSAttributedStringKey,id> * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) {
if ([attrs objectForKey:NSAttachmentAttributeName]) {
NSTextAttachment *attachement = [attrs objectForKey:NSAttachmentAttributeName];
CGRect rect = [weakSelf boundingRectForCharacterRange:range];
NSLog(@"===========%@",NSStringFromCGRect(rect));
MSHTMLImgModel *model = [MSHTMLImgModel new];
model.rect = rect;
// 获取附件image
model.image = [UIImage imageWithData:attachement.fileWrapper.regularFileContents] ;
[arr addObject:model];
}
if (range.location + range.length == htmlStr.length){
weakSelf.arr = arr;
}
}];
}
5、判断点击事件,显示大图
- 1、获取点击的点在label内的point
UIGestureRecognizer.h
-(CGPoint)locationInView:(nullable UIView*)view;
- 2、判断point是否某个范围内
CG_EXTERN bool CGRectContainsPoint(CGRect rect, CGPoint point)
- 3、整合代码
- (void)tapLabel:(UITapGestureRecognizer *)sender{
CGPoint point = [sender locationInView:self];
NSLog(@"handleSingleTap!pointx:%f,y:%f",point.x,point.y);
MSHTMLImgModel *currentModel = nil;
// 循环遍历数组进行判断
for (MSHTMLImgModel *model in self.arr) {
if (CGRectContainsPoint(model.rect, point)){
currentModel = model;
break;
}else{
continue;
}
}
if (currentModel) {
获取到了图片(currentModel.image)
我们可以通过图片浏览器等进行点击查看大图操作。具体不在详述。
}
}
6、优化
我们可能会在多个地方用到这个逻辑,我目前想到的方式是封装一个label。
demo地址
https://github.com/msbaby520/MSHTMLImg