需求如下:
【生效时间】和【办理号码】的高度可以计算。
【图文介绍】返回的是一串 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 ;
}
加载出来的效果如下:
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 也就是浏览器窗口高度值(这是它的最小值);