美文网首页
UITableViewCell 加载 HTML 代码

UITableViewCell 加载 HTML 代码

作者: biubiu15 | 来源:发表于2018-03-19 22:30 被阅读0次

    需求如下:


    需求.jpeg

    【生效时间】和【办理号码】的高度可以计算。
    【图文介绍】返回的是一串 HTML 代码,类似 "<span style="font-size:14px;color:#000000;">\U3010\U8d44\U8d39\U6807\U51c6\U3011</span><br />" 这样的代码。
    加载 HTML 代码,可用 UILabel 或者 UIWebView,难点在于对高度的计算。

    UILabel 加载 HTML

    label 加载 HTML 的原理是把HTML转成富文本,在赋值给
    label.attributedText
    HTML 转富文本的代码如下:

        NSDictionary *options = @{ NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType,
                                   NSCharacterEncodingDocumentAttribute :@(NSUTF8StringEncoding) };
        
        // htmlString 为需加载的HTML代码
        NSData *data = [htmlString dataUsingEncoding:NSUTF8StringEncoding];
        
        _label.attributedText = [[NSAttributedString alloc] initWithData:data options:options documentAttributes:nil error:nil];
    

    此时可计算出文本高度,代码如下:

    CGFloat attriHeight = [_label.attributedText boundingRectWithSize:CGSizeMake(SCREEN_WIDTH - 30*layoutBy6(), CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin context:nil].size.height;
    

    可用类方法返回Cell的高度

    // cell的高度
    +(CGFloat)getCellHeight:(NSString*)htmlStr {
        
        NSDictionary *options = @{ NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType,
                                   NSCharacterEncodingDocumentAttribute :@(NSUTF8StringEncoding)
                                   };
        NSData *data = [htmlStr dataUsingEncoding:NSUTF8StringEncoding];
        NSAttributedString *attrStr =  [[NSAttributedString alloc] initWithData:data options:options documentAttributes:nil error:nil];
    
        CGFloat attriHeight = [attrStr boundingRectWithSize:CGSizeMake([UIScreen mainScreen].bounds.size.width - 30, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin context:nil].size.height;
        
        return attriHeight ;
    }
    

    加载出来的效果如下:


    UILabel加载效果.png
    UIWebView 加载 HTML

    UIWebView 加载 HTML 的方法很简单,就一句代码

    [_webView loadHTMLString:desStr baseURL:nil];
    

    但此时并不知道 webView 的高度,需要通过 UIWebViewDelegate 的代理方法获取高度。

    - (void)webViewDidFinishLoad:(UIWebView *)webView {
        CGFloat webViewHeight = [[webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"] floatValue];
        _webView.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, webViewHeight);
    }
    

    由于高度必须在 webView 完成加载之后才能获取得到,当获取到高度之后,需要通知 tableView reloadData。然而,tableView 刷新会对该 Cell 重新赋值,Cell 赋值导致 webView 又完成一遍加载。。。程序陷入了死循环。
    避免该情况,对需要加载的内容提前赋值给 Cell。不要在tableview cellForRowAtIndexPath 方法里赋值,网络请求回来后就赋值。把 webViewCell 懒加载,Block 里面执行 tableView section 更新。

    Cell 的代码如下👇

    @interface WebViewCell : UITableViewCell
    <UIWebViewDelegate>
    
    @property (nonatomic , copy) NSString *webContentStr; 
    
    @property (nonatomic , assign) CGFloat cellHeight;  
    
    @property (nonatomic, copy) void(^Block)(void);   // Block回调
    
    @end
    
    @implementation WebViewCell
    
    #pragma mark setter
    -(void)setWebContentStr:(NSString *)webContentStr {
        _webContentStr = webContentStr;
        // 移除所有视图
        [self.contentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
        // 创建 WebView ,webView 须给初始值,在 delegate 再更改 frame
        UIWebView *webView = [[UIWebView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, 1)];
        webView.scrollView.scrollEnabled = NO;
        webView.delegate =self;
        [webView sizeToFit];
        [self.contentView addSubview:webView];
        //加载Html文件
        [webView loadHTMLString:desStr baseURL:nil];
    }
    
    #pragma mark UIWebViewDelegate
    - (void)webViewDidFinishLoad:(UIWebView *)webView {
        //加载完成后获取WebView实际高度
        CGFloat webViewHeight = [[webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"] floatValue];
        webView.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, webViewHeight);
        
        self.cellHeight = webViewHeight;
        if (self.Block) {
            self.Block();
        }
    }
    
    @end
    

    VC 部分的代码👇

    @property (nonatomic, strong) WebViewCell *webCell;
    
    
    #pragma mark net request
    - (void)gainWebContent {
      self.webCell.webContentStr = 网络请求回来的数据;
    }
    
    #pragma mark tableView
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
        return self.webCell.cellHeight;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        if (indexPath.section == 2) {
            return self.webCell;
        }
    }
    
    #pragma mark lazy load
    - (WebCell *)webCell{
        if (!_webCell) {
            NSString *cellIdentifier = @"webCell";
             _webCell = [[WebCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
            //回调刷新Cell内容及高度
            __weak typeof(self) weakSelf = self;
            _webCell.Block = ^{
                __strong typeof(self) strongSelf = weakSelf;
                [strongSelf.tableView reloadSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationNone];
            };
        }
        return _webCell;
    }
    
    题外话

    @"document.body.scrollHeight" 中的 scrollHeight。有的资料里面,这里的语句是 @"document.body.offsetHeight"。稍微查了一下 offsetHeight 和 scrollHeight 的区别:

    1)document.documentElement.scrollHeight = document.documentElement.offsetHeight => 就是整个网页文档body的高度,随着网页内容的多少变化,包括网页内的所有border,margin,padding;

    2)body.clientHeight = body.offsetHeight => body的内容高度,不包括margin和border值,实际上就是body的height值;

    3)body.scrollHeight => 包括body的margin,body值
    a 当网页内容超出浏览器可视窗口高度值时,= body.clientHeight+margin+border = document.documentElement.scrollHeight ;
    b 当网页内容较少未超出时,= document.documentElement.clientHeigh 也就是浏览器窗口高度值(这是它的最小值);

    相关文章

      网友评论

          本文标题:UITableViewCell 加载 HTML 代码

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