一,先计算WebView的内容高度
1,想当然的方法1
既然想计算webView中网页的高度,那就在网页加载完成的时候,直接返回
scrollView.contentSize.height。
#pragma mark - WKNavigationDelegate
// 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
NSLog(@"加载完成");
CGFloat contentHeight = self.webView.scrollView.contentSize.height;
}
这个结果返回值:是0。
为啥不行,这里面先理解成这里的加载完成只是网页请求解析完成,还没有放在WebView的scrollView上显示!
2,一般方法
一般我们计算webView的高度,网上有栗子是通过调用网页的方法来实现,如下:
#pragma mark - WKNavigationDelegate
// 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
NSLog(@"加载完成");
[webView evaluateJavaScript:@"document.body.scrollHeight"completionHandler:^(id _Nullable result,NSError * _Nullable error){
_wbContentHeight = [result floatValue];
NSLog(@"scrollHeight高度:%.2f",[result floatValue]);
}];
[webView evaluateJavaScript:@"document.body.offsetHeight"completionHandler:^(id _Nullable result,NSError * _Nullable error){
NSLog(@"offsetHeight高度:%.2f",[result floatValue]);
}];
}
2016-11-08 11:41:50.572862 WebView内容高度计算[18606:6890472] scrollHeight高度:5497.00
2016-11-08 11:41:50.574534 WebView内容高度计算[18606:6890472] offsetHeight高度:5465.00
通过调用html的body标签的属性,我们去确实可以获取高度,这里分别用了:scrollHeight
和 offsetHeight
。如果想要计算webView上scrollView的contentSize的height 那么用scrollHeight
这个计算还是挺准确的,这个offsetHeight
计算的会查几十个高度(网页不同差的不同,这个原因我不知道)。
但是,这只是一般方法,只能说如果你的web页面是你们的H5工程师给你们写的(其实特指页面不能缩放的),那是可以的,没问题。如果你的页面是顺便一个网页,比如oschina主页https://www.oschina.net,这会你计算,这个方法返回的值和你scrollView真正能滚动的区域就差很远了!
为什么了?
因为我们的WKWebView会根据网页的大小来自动缩放网页(UIWebView可以通过设置scalesPageToFit
来开启),而这个方法计算的是缩放前的网页滚动区域大小,所以我们如果想计算出缩放后的高度,就要算出缩放比,然后乘上这个缩放比。关键是这个缩放比怎么拿?UIWebView我们没有直接属性可拿这个缩放比,而WKWebView有magnification
属性但是phone不可用😱,我们可以算出宽度,再根据webView的宽度算出,下面是代码
#pragma mark - WKNavigationDelegate
// 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
NSLog(@"加载完成");
//这个方法也可以计算出webView滚动视图滚动的高度
[webView evaluateJavaScript:@"document.body.scrollWidth"completionHandler:^(id _Nullable result,NSError * _Nullable error){
CGFloat ratio = CGRectGetWidth(self.wkWebView.frame) /[result floatValue];
NSLog(@"scrollWidth高度:%.2f",[result floatValue]);
[webView evaluateJavaScript:@"document.body.scrollHeight"completionHandler:^(id _Nullable result,NSError * _Nullable error){
NSLog(@"scrollHeight高度:%.2f",[result floatValue]*ratio);
}];
}];
}
3,终极方法
有没有更好的方法,当然有!哈哈哈哈,及时使用KVO,监听scrollView.contentSize
[self.wbScrollView addObserver:self forKeyPath:@"contentSize"
options:NSKeyValueObservingOptionNew context:nil];
#pragma mark - KVO回调
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
//更具内容的高重置webView视图的高度
NSLog(@"Height is changed! new=%@", [change valueForKey:NSKeyValueChangeNewKey]);
NSLog(@"tianxia :%@",NSStringFromCGSize(self.wbScrollView.contentSize));
CGFloat newHeight = self.wbScrollView.contentSize.height;
控制台输出
2016-11-09 17:28:25.850029 WebView内容高度计算[19613:7236291] Height is changed! new=NSSize: {998, 2740}
2016-11-09 17:28:25.850227 WebView内容高度计算[19613:7236291] tianxia :{998, 2740}
2016-11-09 17:28:25.850916 WebView内容高度计算[19613:7236291] Height is changed! new=NSSize: {320, 878.5}
2016-11-09 17:28:25.850987 WebView内容高度计算[19613:7236291] tianxia :{320, 878.5}
2016-11-09 17:28:25.927509 WebView内容高度计算[19613:7236291] Height is changed! new=NSSize: {320, 878.5}
2016-11-09 17:28:25.927660 WebView内容高度计算[19613:7236291] tianxia :{320, 878.5}
2016-11-09 17:28:25.927836 WebView内容高度计算[19613:7236291] Height is changed! new=NSSize: {320, 878.5}
第一次计算出的2740就是通过方法2不乘以缩放比得到的值!
二,下方放入TableView做评论列表
1,解决webView 和 table滚动的协调性
思路就是,把WebView作为TableView的TableHeader。这里我们控制WebView最高也就是屏幕的高,如果内容大于WebView的高度(所以有了上面计算webView的内容高度),需要滚动显示WebView的内容,直到滚动到最底端的时候,才滚动出tableView!
初始状态控制:
初始状态我们需要把webView的scrollView的回弹bounces一直禁止掉,防止和TableView的回弹冲突。
self.wbScrollView = self.wkWebView.scrollView;
self.wbScrollView.bounces = NO;
我们只需要监听tableView的滚动事件,在他的偏移度为<<=0的时候,我们要让webView的scrollVIew可以滚动,同时关闭tableView的回弹bounces,在table的偏移度>0的时候,就取反,这样我们可以控制webView和table滚动的协调性。
#pragma mark - UIScrollViewDelegate
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
if ([scrollView isEqual:self.tableView]) {
NSLog(@"tableView");
CGFloat yOffSet = scrollView.contentOffset.y;
NSLog(@"偏移%.2f",yOffSet);
if (yOffSet <= 0) {
self.wbScrollView.scrollEnabled = YES;
self.tableView.bounces = NO;
}else{
self.wbScrollView.scrollEnabled = NO;
self.tableView.bounces = YES;
}
}
}
2,解决网页动态加载内容高度变化问题
网页加载的时候在加载完成会调用webView 的delegate ,这时候我们可以计算出网页的高度,重置我的webView的frame 的高(使用方法2),但是我们可能会忽视一个问题,如果网页中有图片的话,因为图片大多数都是异步加载的,在webView加载完成的时候计算出的内容高度并不包含图片的高度,所以我们要设置一个监听KVO,来监听内容高度的变化!
#pragma mark - WKNavigationDelegate
// 页面加载完成之后调用
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
NSLog(@"加载完成");
//这个方法也可以计算出webView滚动视图滚动的高度
[webView evaluateJavaScript:@"document.body.scrollWidth"completionHandler:^(id _Nullable result,NSError * _Nullable error){
NSLog(@"scrollWidth高度:%.2f",[result floatValue]);
CGFloat ratio = CGRectGetWidth(self.wkWebView.frame) /[result floatValue];
[webView evaluateJavaScript:@"document.body.scrollHeight"completionHandler:^(id _Nullable result,NSError * _Nullable error){
NSLog(@"scrollHeight高度:%.2f",[result floatValue]);
NSLog(@"scrollHeight计算高度:%.2f",[result floatValue]*ratio);
CGFloat newHeight = [result floatValue]*ratio;
[self resetWebViewFrameWithHeight:newHeight];
//KVO监听网页内容高度变化
if (newHeight < CGRectGetHeight(self.view.frame)) {
//如果webView此时还不是满屏,就需要监听webView的变化 添加监听来动态监听内容视图的滚动区域大小
[self.wbScrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];
}
}];
}];
}
在监听回调中,重置(Reset) webView的frame。
#pragma mark - KVO回调
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
//更具内容的高重置webView视图的高度
CGFloat newHeight = self.wbScrollView.contentSize.height;
NSLog(@"kvo算出的高度啊:%.f",newHeight);
[self resetWebViewFrameWithHeight:newHeight];
}
这样我们就可以完美的把webView和tableView衔接起来了!
顺便说一下,重置完webView的frame要刷新table 因为webView是table的header!
完整代码下载地址:<链接: https://pan.baidu.com/s/1oGs1tE1JIryVdQKgQrdGEg 密码: rgff>
代码中,方案二是这篇博客,方案一思路是一个scrollView上面放webView下面放tableView,发现在控制滚动冲突上不是多理想