DTCoreText的集成与使用

作者: 梧雨北辰 | 来源:发表于2018-01-30 13:55 被阅读1217次

    DTCoreText是可以将HTML字符串转化为富文本使用的工具,既保证原生实现又能适应灵活的样式修改,而且相比于使用WebView显示内容在性能上也有很大优势。本篇就这一技术的使用进行总结。

    目录

    一、相关资源
    二、DTCoreText的集成
    三、DTCoreText的使用
    四、可能遇到的错误
    五、参考链接

    一、相关资源

    1. DTCoreText源码下载
    2. DTCoreText官方文档
    3. DTCoreText集成文档
    4. 本文DTCoreText测试工程

    温馨提示:文中代码量比较大,看起来可能比较费劲,所以先将本文的Demo链接放在这里,结合代码看更方便,毕竟代码才是硬道理嘛!

    二、DTCoreText的集成

    在项目中使用DTCoreText需要它的两个静态库:DTCoreText.framework和DTFoundation,framework。但是从Github下载的文件却不能直接使用。起初我是直接从网上其他地方下载打包好的静态库来使用的,但这样会遗漏掉更新。所以还是总结了集成DTCoreText的具体步骤如下:

    1.下载源码

    创建一个文件夹DTCoreText,使用终端命令下载源码:

    git clone --recursive [https://github.com/Cocoanetics/DTCoreText.git](https://github.com/Cocoanetics/DTCoreText.git) Externals/DTCoreText
    

    2.设置编译配置

    使用下载的工程可以根据需求修改编译配置,然后运行工程得到适合不同平台的静态库。为了获取到适合iOS设备使用的SDK,我们选择工程Target为DTCoreText(iOS),并依次选择工程->TARGETS->DTCoreText(iOS)->Deployment Info,选择需要最低支持的系统版本

    image.png

    3.设置Scheme

    将Run环境修改为Release模式,依次选择Product->Scheme->Edit Scheme

    image.png

    4.模拟器和真机分别编译

    使用commadn+B执行代码编译,注意一定要选择正确的Target,我们既然是用于iOS,就应该选择DTCoreText (iOS)这个Target进行编译

    真机环境编译.png 模拟器环境编译.png

    5.打开编译缓存,获取静态库

    在Xcode依次打开File->File Setting->DerivedData,然后点击之后的路径箭头可以找到DTCoreText的编译缓存文件夹

    屏幕快照 2018-01-30 下午2.01.52.png

    然后我们再依次打开Build->Products,将会看到适合模拟器和真机使用的两个静态库文件夹:

    image.png

    6.合并静态库

    经过上述步骤,我分别得到了适合模拟器和真机使用的静态库,现在我们把它们合并。首先我们把Products文件拷贝到一个合适的位置,然后在控制台执行合并静态库的命令如下:

    合并静态库.png

    如图,我们使用lipo -create命令合并了适合模拟器和真机使用的可执行文件并放在了桌面上如下:

    image.png

    然后我们需要将两个文件分别对应拷贝到Release-iphones文件夹中的DTCoreText.framework和DTFoundation.framework中。这样最终我们就得到想要的静态库。

    三、DTCoreText的使用

    在这之前我们准备一段测试用的Html如下:

    _html = @"<span style=\"color:#333;font-size:15px;\"><strong>标题1</strong></span><br/><span align=\"left\" style=\"color:#333;font-size:15px;\">详细介绍详细介绍详细介绍详细介绍详细介绍详细介绍。</span><br/><img src=\"http://cn-qinqimaifang-uat.oss-cn-hangzhou.aliyuncs.com/img/specialist/upload/spcetiicwlz1v_54e2e00fa8a6faf66168571654dbfee2.jpg\" _src=\"http://cn-qinqimaifang-uat.oss-cn-hangzhou.aliyuncs.com/img/specialist/upload/spcetiicwlz1v_54e2e00fa8a6faf66168571654dbfee2.jpg\"><br/><br/><span style=\"color:#333;font-size:15px;\">百度:<a href=\"http://www.baidu.com.cn\">my testlink</a></span><br/><br/><span style=\"color:#333;font-size:15px;\">电话:<a href=\"tel:4008001234\">my phoneNum</a></span><br/><br/><span style=\"color:#333;font-size:15px;\">我邮箱:<a href=\"mailto:dreamcoffeezs@163.com\">my mail</a></span>";
    

    关于DTCoreText,我们主要用到它的三个控件,分别是DTAttributedLabel,DTAttributedTextView和DTAttributedTextCell。下面对它们的使用进行具体说明:

    1.DTAttributedLabel

    顾名思义,我们也会把DTAttributedLabel当做一个UILabel来使用(虽然事实上DTAttributedLabel并不属于UILabel的子类)。这里针对DTAttributedLabel使用的三个问题进行介绍。

    1.1显示基本文本

    //1.创建DTAttributedLabel
    _attributedLabel = [[DTAttributedLabel alloc] initWithFrame:CGRectZero];
    _attributedLabel.delegate = self;
    [self.view addSubview:self.attributedLabel];
    
    //2.Html转化富文本
    NSData *data = [_html dataUsingEncoding:NSUTF8StringEncoding];
    NSAttributedString *attributedString = [[NSAttributedString alloc] initWithHTMLData:data documentAttributes:NULL];
    
    //3.计算Frame
    //预设一个最大的Frame,限宽不限高,方便以后计算布局
    _viewMaxRect =  CGRectMake(15, 15, ZSToolScreenWidth - 15*2, CGFLOAT_HEIGHT_UNKNOWN);        
    DTCoreTextLayouter *layouter = [[DTCoreTextLayouter alloc] initWithAttributedString:attributedString];
    NSRange entireStringRange = NSMakeRange(0, [attributedString length]);
    DTCoreTextLayoutFrame *layoutFrame = [layouter layoutFrameWithRect:_viewMaxRect range:entireStringRange];
    CGSize textSize = [layoutFrame frame].size;
    self.attributedLabel.frame = CGRectMake(_viewMaxRect.origin.x, _viewMaxRect.origin.y, _viewMaxRect.size.width, textSize.height);
      
    //4.设置富文本
    self.attributedLabel.attributedString = [self getAttributedStringWithHtml:self.html];
    

    1.2显示图片

    既然是富文本,DTAttributedLabel也会显示图片。但是如果我们的Html字符串里图片链接没有包含大小,图片并不能正常显示。为了显示图片我们需要懒加载获取宽高再刷新显示,这就需要用到DTAttributedLabel的代理方法如下:

    #pragma mark - Delegate:DTAttributedTextContentViewDelegate
    //DTCoretText在解析Html的时候,如果遇到网络图片会插入一个占位符
    //对于图片类型(DTImageTextAttachmentd)的占位符,我们使用DTLazyImageView来显示
    - (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedTextContentView viewForAttachment:(DTTextAttachment *)attachment frame:(CGRect)frame{
        if([attachment isKindOfClass:[DTImageTextAttachment class]]){
            NSString *imageURL = [NSString stringWithFormat:@"%@", attachment.contentURL];
            DTLazyImageView *imageView = [[DTLazyImageView alloc] initWithFrame:frame];
            imageView.delegate = self;//图片懒加载代理
            imageView.contentMode = UIViewContentModeScaleAspectFit;
            imageView.image = [(DTImageTextAttachment *)attachment image];
            imageView.url = attachment.contentURL;
    
            //处理gif图片
            if ([imageURL containsString:@"gif"]) {
               dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                    NSData *gifData = [NSData dataWithContentsOfURL:attachment.contentURL];
                    dispatch_async(dispatch_get_main_queue(), ^{
                        imageView.image = DTAnimatedGIFFromData(gifData);
                    });
                });
            }
            return imageView;
        }
        return nil;
    }
    
    #pragma mark  Delegate:DTLazyImageViewDelegate
    //懒加载图片代理
    - (void)lazyImageView:(DTLazyImageView *)lazyImageView didChangeImageSize:(CGSize)size {
        NSURL *url = lazyImageView.url;
        CGSize imageSize = size;
        NSPredicate *pred = [NSPredicate predicateWithFormat:@"contentURL == %@", url];
        BOOL didUpdate = NO;
        
        //update all attachments that match this URL (possibly multiple images with same size)
        //更新所有匹配URL的占位符视图 
        for (DTTextAttachment *oneAttachment in [self.attributedLabel.layoutFrame textAttachmentsWithPredicate:pred]){
            //update attachments that have no original size, that also sets the display size
            //更新没有自带尺寸的占位视图(如网络图片) 
            if (CGSizeEqualToSize(oneAttachment.originalSize, CGSizeZero)){
                //原始图片不带宽高,被识别后修改Html
                oneAttachment.originalSize = imageSize;
              //使用新拿到的图片尺寸更新HTML字符串 
                [self configNoSizeImageView:url.absoluteString size:imageSize];
                didUpdate = YES;
            }
        }
        if (didUpdate){    
            //重新显示富文本
            CGSize textSize = [self getAttributedTextHeightHtml:self.html with_viewMaxRect:_viewMaxRect];
            self.attributedLabel.frame = CGRectMake(_viewMaxRect.origin.x, _viewMaxRect.origin.y, _viewMaxRect.size.width, textSize.height);
            self.attributedLabel.attributedString = [self getAttributedStringWithHtml:self.html];
            self.attributedLabel.layouter = nil;
            [self.attributedLabel relayoutText];
        }
    }
    
    #pragma mark - private Methods
    //使用得到的新图片尺寸,更新HtmlString字符串
    - (void)configNoSizeImageView:(NSString *)url size:(CGSize)size{
        //_viewMaxRect是预设的最大Frame
        CGFloat imgSizeScale = size.height/size.width;
        CGFloat widthPx = _viewMaxRect.size.width;
        CGFloat heightPx = widthPx * imgSizeScale;
        NSString *imageInfo = [NSString stringWithFormat:@"_src=\"%@\"",url];
        NSString *sizeString = [NSString stringWithFormat:@"style=\"width:%.fpx; height:%.fpx;\"",widthPx,heightPx];
        NSString *newImageInfo = [NSString stringWithFormat:@"_src=\"%@\"%@",url,sizeString];
        if ([self.html containsString:imageInfo]) {
            NSString *newHtml = [self.html stringByReplacingOccurrencesOfString:imageInfo withString:newImageInfo];
            self.html = newHtml;
        }
    }
    
    //使用HtmlString,和预设的Frame,计算富文本视图自适应后的高度
    - (CGSize)getAttributedTextHeightHtml:(NSString *)htmlString with_viewMaxRect:(CGRect)_viewMaxRect{
        //获取富文本
        NSAttributedString *attributedString =  [self getAttributedStringWithHtml:htmlString];
        //获取布局器
        DTCoreTextLayouter *layouter = [[DTCoreTextLayouter alloc] initWithAttributedString:attributedString];
        NSRange entireString = NSMakeRange(0, [attributedString length]);
        //获取Frame
        DTCoreTextLayoutFrame *layoutFrame = [layouter layoutFrameWithRect:_viewMaxRect range:entireString];
        //得到大小
        CGSize sizeNeeded = [layoutFrame frame].size;
        return sizeNeeded;
    }
    

    1.3响应事件

    如果我们希望在DTAttributedLabel上操作点击事件,那么对应的我们也应该在Html中使用超链接A标签。这里我们需要用到如下的代理方法如下:

    - (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedTextContentView
                              viewForLink:(NSURL *)url
                               identifier:(NSString *)identifier
                                    frame:(CGRect)frame{
        //此方法需要我们在这里返回一个可以点击响应的控件如Button,然后就可以很方便的处理响应事件了,其中:
        //url:Html中的超链接(可以根据需要设置http、tel、mailto等)
        //identifier:属于该视图的唯一性标识
        //frame:超链接字符串所在的位置,需要将自定义响应按钮设置为此Frame
        return nil;
    }
    

    注意:如果我们需要显示一些输入框之类的视图,也可以借助此方法。
    最终效果图:

    屏幕快照 2018-01-30 下午2.24.32.png

    2.DTAttributedTextView

    其实,DTAttributedTextView和DTAttributedLabel的用法几乎一样。从其源码上就能看出,DTAttributedLabel继承于DTAttributedTextContentView的,而DTAttributedTextView包含DTAttributedTextContentView属性。可以说DTAttributedTextView就是借助DTAttributedLabel实现的视图。

    DTAttributedTextView是支持滑动显示的富文本视图,在使用时计算富文本的Frame也就没那么必要了,一般我们都会指定它的Frame。其在这里的用法就不累述了。

    3.DTAttributedTextCell

    如果我们需要在单元格上显示富文本,DTCoretText也为我们提供了特有的类来解决这个问题,那就是DTAttributedTextCell。通过这个单元格类,我们可以方便的设置富文本以及获取单元格高度。以下是使用DTAttributedTextCell显示富文本的核心代码:

    3.1. 声明控制器内属性

    @interface TestTableViewController ()<UITableViewDataSource,UITableViewDelegate,DTAttributedTextContentViewDelegate,DTLazyImageViewDelegate>
    @property(nonatomic,strong)UITableView *tableView;
    //普通单元格与富文本单元格
    @property (nonatomic, copy) NSString *cellID_Normal;
    @property (nonatomic, copy) NSString *cellID_DTCoreText;
    //类似tabelView的缓冲池,用于存放图片大小
    @property (nonatomic, strong) NSCache *imageSizeCache;
    @property (nonatomic,strong)NSCache *cellCache;
    //表视图数据源
    @property (nonatomic, strong) NSArray  *dataSource;
    //当前表视图是否在滑动
    @property (nonatomic,assign)BOOL isScrolling;
    
    @end
    

    3.2.表视图代理方法返回单元格及其高度

    //代理方法:返回单元格
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        switch (indexPath.section) {
            case 0:{
                //普通单元格
                UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:_cellID_Normal];
                cell.textLabel.text = self.dataSource[indexPath.section][indexPath.row];
                return cell;
                break;
            }
            case 1:{
                //自定义方法,创建富文本类型的单元格
                ZSDTCoreTextCell *dtCell = (ZSDTCoreTextCell *) [self tableView:tableView prepareCellForIndexPath:indexPath];
                return dtCell;
                break;
            }
            default:
                break;
        }
        return nil;
    }
    
    //返回单元格高度
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(nonnull NSIndexPath *)indexPath{
        switch (indexPath.section) {
            case 0:{
                return 50;
                break;
            }
            case 1:{
              //返回富文本类型单元格的方法
                ZSDTCoreTextCell *cell = (ZSDTCoreTextCell *)[self tableView:tableView prepareCellForIndexPath:indexPath];
                return [cell requiredRowHeightInTableView:tableView];
                break;
            }
            default:
                break;
        }
        return 0;
    }
    

    3.3.懒加载处理无宽高属性的图片

    #pragma mark - DTAttributedTextContentViewDelegate
    //对于没有在Html标签里设置宽高的图片,在这里为其设置占位
    - (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedTextContentView viewForAttachment:(DTTextAttachment *)attachment frame:(CGRect)frame{
        if([attachment isKindOfClass:[DTImageTextAttachment class]]){
            //自定义的ZSDTLazyImageView继承于DTLazyImageView,增加了一个属性textContentView
            //用于更新图片大小
            ZSDTLazyImageView *imageView = [[ZSDTLazyImageView alloc] initWithFrame:frame];
            imageView.delegate = self;
            imageView.image = [(DTImageTextAttachment *)attachment image];
            imageView.textContentView = attributedTextContentView;
            imageView.url = attachment.contentURL;
            return imageView;
        }
        return nil;
    }
    
    
    //对于无宽高的图片懒加载,缓存记录其大小,然后执行表视图更新
    - (void)lazyImageView:(ZSDTLazyImageView *)lazyImageView didChangeImageSize:(CGSize)size{
        BOOL needUpdate = NO;
        NSURL *url = lazyImageView.url;
        NSPredicate *pred = [NSPredicate predicateWithFormat:@"contentURL == %@", url];
        /* update all attachments that matchin this URL (possibly multiple
            images with same size)
         */
        for (DTTextAttachment *oneAttachment in [lazyImageView.textContentView.layoutFrame textAttachmentsWithPredicate:pred]){
            // update attachments that have no original size, that also sets the display size
            if (CGSizeEqualToSize(oneAttachment.originalSize, CGSizeZero)){
                oneAttachment.originalSize = size;
                NSValue *sizeValue = [_imageSizeCache objectForKey:oneAttachment.contentURL];
                if (!sizeValue) {
                    //将图片大小记录在缓存中,但是这种图片的原始尺寸可能很大,所以这里设置图片的最大宽
                    //并且计算高
                    CGFloat aspectRatio = size.height / size.width;
                    CGFloat width = ZSToolScreenWidth - 15*2;
                    CGFloat height = width * aspectRatio;
                    CGSize newSize = CGSizeMake(width, height);
                    [_imageSizeCache setObject:[NSValue valueWithCGSize:newSize]forKey:url];
                }
                needUpdate = YES;
            }
        }
        if (needUpdate){
            //有新的图片尺寸被缓存记录的时候,需要刷新表视图
            [self reloadCurrentCell];
        }
    }
    

    3.4.创建富文本单元格的方法

    #pragma mark - private Methods
    //创建富文本单元格,并更新单元格上的数据
    //ZSDTCoreTextCell是自定义的继承于DTCoreTextCell的单元格
    - (ZSDTCoreTextCell *)tableView:(UITableView *)tableView prepareCellForIndexPath:(NSIndexPath *)indexPath{
        NSString *key = [NSString stringWithFormat:@"dtCoreTextCellKEY%ld-%ld", (long)indexPath.section, (long)indexPath.row];
        ZSDTCoreTextCell *cell = [_cellCache objectForKey:key];
        if (!cell){
            cell = [[ZSDTCoreTextCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:_cellID_DTCoreText];
            cell.attributedTextContextView.edgeInsets = UIEdgeInsetsMake(0, 15, 0, 15);
            [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
            cell.accessoryType = UITableViewCellAccessoryNone;
            cell.hasFixedRowHeight = NO;
            cell.textDelegate = self;
            cell.attributedTextContextView.shouldDrawImages = YES;
            //记录在缓存中
            [_cellCache setObject:cell forKey:key];
        }
        //2.设置数据
        //2.1为富文本单元格设置Html数据
        [cell setHTMLString:self.dataSource[indexPath.section][indexPath.row]];
        //2.2为每个占位图(图片)设置大小,并更新
        for (DTTextAttachment *oneAttachment in cell.attributedTextContextView.layoutFrame.textAttachments) {
            NSValue *sizeValue = [_imageSizeCache objectForKey:oneAttachment.contentURL];
            if (sizeValue) {
                cell.attributedTextContextView.layouter=nil;
                oneAttachment.displaySize = [sizeValue CGSizeValue];
                [cell.attributedTextContextView relayoutText];
            }
        }
        [cell.attributedTextContextView relayoutText];
        return cell;
    }
    

    3.5.处理表视图的刷新

    如果当前表视图在滑动就不执行刷新,因为滑动时候会自动调用表视图的刷新方法

    - (void)reloadCurrentCell{
        if (self.isScrolling) {
            return;
        }
        //如果当前表视图没有在滑动,就手动刷新当前在屏幕显示的单元格
        NSArray *indexPaths = [self.tableView indexPathsForVisibleRows];
        if(indexPaths){
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
            });
        }
    }
    
    - (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView{
        _isScrolling = NO;
    }
    
    - (void)scrollViewDidScroll:(UIScrollView *)scrollView{
        _isScrolling = YES;
    }
    

    3.6.set方法创建表视图与数据源

    #pragma mark - set/get方法
    - (UITableView *)tableView{
        if (_tableView == nil) {
            _tableView = [[UITableView  alloc] initWithFrame:CGRectMake(0, 0, ZSToolScreenWidth, ZSToolScreenHeight-64) style:UITableViewStylePlain];
            _tableView.dataSource = self;
            _tableView.delegate = self;
            [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:_cellID_Normal];
            //[_tableView registerClass:[ZSDTCoreTextCell class] forCellReuseIdentifier:_cellID_DTCoreText];
        }
        return _tableView;
    }
    
    - (NSArray *)dataSource{
        if(_dataSource == nil){
            NSMutableArray *noramDataArray = @[].mutableCopy;
            NSMutableArray *htmlDataArray = @[].mutableCopy;
            NSArray *images = @[@"https://i0.hdslb.com/bfs/archive/d5ad3cf95d32f3d2f2e3471a39120237200d84d8.jpg",
                               @"https://i0.hdslb.com/bfs/archive/71d2fed927d9351e759f408ca7d66c556c37a6b4.jpg",
                               @"https://i0.hdslb.com/bfs/archive/7f520b31b67cd5d89dd30b61b40711327bb00288.png",
                               @"https://i0.hdslb.com/bfs/archive/6edbe81bf74c106087ad139aca169d6e8d9d963b.jpg",
                               @"https://i0.hdslb.com/bfs/archive/805aa8f7ae722fcc277f425bb9927e29ec1d2468.jpg",
                               @"https://i0.hdslb.com/bfs/archive/a7c61d94c583363a970d2a2e339eea97f8f32317.jpg",
                               @"https://i0.hdslb.com/bfs/archive/b447ee1fd63b4cf6f4465a5621cc12898867d26b.jpg"];
            for(int i = 0;i<1000;i++){
                if(i <6){
                    [noramDataArray addObject:[NSString stringWithFormat:@"测试普通单元格:%d",i]];
                }
                //这里提供的Html图片链接,没有宽高属性,代码中已经演示了如何处理
                int k = i % 6;
                NSString *htmlString =[NSString stringWithFormat:@"<span style=\"color:#333;font-size:15px;\"><strong>测试富文本单元格%d:</strong></span><br/><span style=\"color:#333;font-size:15px;\">记住!砍价是由你自己先砍,砍不动时再由砍价师继续砍;由砍价师多砍下的部分,才按照下列标准收费:</span><br/><span style=\"color:#333;font-size:15px;\"><img src=%@ _src=%@></span>",i,images[k],images[k]];
                [htmlDataArray addObject:htmlString];
            }
            _dataSource = @[noramDataArray,htmlDataArray];
        }
        return _dataSource;
    }
    

    使用上述方法使用DTAttributedTextCell的效果图如下:


    DTAttributedTextCell效果图

    四、可能遇到的错误

    原本上,在项目中使用只需将Release-iphones的DTCoreText.framework和DTFoundation.framework中拖入工程就可以使用了。然而我们编译工程却会遇到这样一个错误:"image not found”
    解决方法如下图:

    image.png

    五、参考链接

    1.DTCoreText集成:
    https://www.jianshu.com/p/b09d3fa1cd98
    2.DTCoreText使用总结:
    http://duxinfeng.com/2017/08/02/DTCoreText%E4%BD%BF%E7%94%A8%E6%80%BB%E7%BB%93/
    3.iOS富文本框架DTCoreText在UITableView上的使用
    http://blog.csdn.net/lala2231/article/details/50780842
    4.CoretText的优缺点
    https://www.jianshu.com/p/6f8162537975

    相关文章

      网友评论

      • asde1234:你好,请问下DTAttributedTextCel里如果要添加其他子控件,比如像微博那种样式的cell,这个该怎么解决呢?
      • 北海有鱼w:楼主你好,我想问下图片的代理方法不执行是怎么回事,已经设置了xxx.textDelegate = self;了
        北海有鱼w:@梧雨北辰 我用你的html可以 用我自己的html不行 我怀疑是html的问题,你有联系方式吗,具体看下什么原因
        梧雨北辰:textDelegate: A delegate implementing DTAttributedTextContentViewDelegate to provide custom subviews for images and links.
        这个是自定义视图的
        梧雨北辰:demo里不行吗?
      • zxFlyer:你好,用DTAttributedTextCell加载图片的时候有没有办法就像SDWebImage一样加载占位图呢?
        梧雨北辰:@zxFlyer 这样的话,我试了下从ZSDTLazyImageView这个类上解决,思路是这样的:给ZSDTLazyImageView上添加默认占位图DefaultImgView,然后KVO监听image属性的变化,存在image时隐藏默占位图,不存在image时显示占位图。这里粘贴代码不方便,有qq什么的话,我发你测试代码,你再试试
        zxFlyer:@梧雨北辰 你好,我昨天试过了,这样添加默认图片没法继续加载URL,我看了源码有image的时候就不会继续请求url了。
        源码:
        if (_displaySize.width==0 || _displaySize.height==0)
        {
        DTImage *image = _image;

        // let's check if we have a cached image already then we can inspect that
        if (!_image)
        {
        image = [[DTImageTextAttachment sharedImageCache] objectForKey:[contentURL absoluteString]];
        }

        if (!image)
        {
        // only local files we can directly load without punishment
        if ([contentURL isFileURL])
        {
        #if TARGET_OS_IPHONE
        NSString *ext = [[[contentURL lastPathComponent] pathExtension] lowercaseString];

        if ([ext isEqualToString:@"gif"])
        {
        image = DTAnimatedGIFFromFile([contentURL path]);
        }
        else
        #endif
        {
        image = [[DTImage alloc] initWithContentsOfFile:[contentURL path]];
        }
        }

        // cache that for later
        if (image)
        {
        [[DTImageTextAttachment sharedImageCache] setObject:image forKey:[contentURL absoluteString]];
        }
        }

        // we have an image, so we can set the original size and default display size
        if (image)
        {
        _contentURL = nil;
        [self _updateSizesFromImage:image];
        }
        }
        梧雨北辰:刚才用代码试了一下,我是这样想的,图片占位:1.首先要给出一个宽高(就像App原生开发的布局);2.提供默认图。
        解决1:在html标签里给图片设置宽高<img src=%@ _src=%@ style=\"width:375px;height:375px\">
        解决2:
        - (UIView *)attributedTextContentView:(DTAttributedTextContentView *)attributedTextContentView viewForAttachment:(DTTextAttachment *)attachment frame:(CGRect)frame{
        if([attachment isKindOfClass:[DTImageTextAttachment class]]){
        ZSDTLazyImageView *imageView = [[ZSDTLazyImageView alloc] initWithFrame:frame];
        imageView.delegate = self;
        //imageView.image = [(DTImageTextAttachment *)attachment image]; //这个为nil,因为是网络图片
        //添加默认图片
        imageView.image = [UIImage imageNamed:@"testImage"];
        imageView.textContentView = attributedTextContentView;
        imageView.url = attachment.contentURL;
        return imageView;
        }
        return nil;
        }
        可以试一下这个思路,看是否能解决问题
      • iYeso:第三个好卡好卡
        北海有鱼w:关于卡顿可以使用缓存高度的策略来判断是不是每次都要计算高度,在cell的model里面缓存高度就好了
        梧雨北辰:是的,因为是使用的Cache的方法管理单元格,暂时我也没想到更好的方法。。。
      • 上升的羽毛:你好,我看你demo里面虽然是自定义的继承DTAttributedTextCell的cell,但是你的cell里面并没有加任何UI控件,我试着加了几个控件上去,导致attributedTextContextView的frame和cell的高度都计算有误。请问怎么解决。因为一般情况下,cell都不会只放显示markdown的view,肯定会有其他的view。
        梧雨北辰:@上升的羽毛 我运行了工程并没有遇到你说的问题,是能够自动刷新的。代码里的表视图的刷新有两种触发:1.每次加载得到图片的宽和高,也就是完整的图片链接;2.滑动的时候刷新。我猜想可能是你自定义了单元格,里面没有处理好图片加载完成之后的刷新吧。还就是有表视图滑动的时候不能调用刷新因为会方法冲突崩溃,这是我当时遇到的一个问题
        上升的羽毛:@风恣 我已经解决自定义控件和富文本混合使用的问题了。现在你的demo还有问题我没解决,就是首次进入页面,前几个cell的图片是不会显示的,需要滑动tableView几次,才会刷新出来。求解。
        梧雨北辰:@上升的羽毛 当时自定义单元格我是为了尝试解决单元格刷新高度的一个bug,后来没用了。我看了官方文档里也没有解释自定义控件和富文本混合使用的做法。我觉的或许可以使用DTAttributedLabel来尝试解决你的问题,在cell里使用DTAttributedLabel来代替富文本的显示,只不过这样对于cell高度的计算要麻烦许多
      • 蜗牛非牛:DTAttributedTextCell加载一次占用CPU就会增加一次,请问有没有好点的解决方案??:pray: :pray: :pray:
        蜗牛非牛:@风恣 好的,谢谢
        梧雨北辰:文章里内容没来得及更新,不过我在github的demo里优化了一下,不知道是否能解决你的问题:https://github.com/DreamcoffeeZS/DTCoreTextDemo
      • lonamessi:膜拜大佬:+1:
      • 李大围:_imageSizeCache 这个是哪来的呢
        梧雨北辰:这是在控制器里声明的一个属性,使用前需要自己初始化。代码太多,没有都粘贴上
      • 李大围:求个demo
        梧雨北辰:就在文章开头,本文Demo: https://github.com/DreamcoffeeZS/DTCoreTextDemo.git 有问题欢迎批评指正

      本文标题:DTCoreText的集成与使用

      本文链接:https://www.haomeiwen.com/subject/owjkvttx.html