iOS UILabel加载html点击图片查看大图 附demo

我们在有些时候,因为性能和加载时间的问题,需要用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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值