UITableViewCell 加载 HTML 代码

需求如下:


UITableViewCell 加载 HTML 代码_第1张图片
需求.jpeg

【生效时间】和【办理号码】的高度可以计算。
【图文介绍】返回的是一串 HTML 代码,类似 "\U3010\U8d44\U8d39\U6807\U51c6\U3011
" 这样的代码。
加载 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 ;
}

加载出来的效果如下:


UITableViewCell 加载 HTML 代码_第2张图片
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


@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 代码)