iOS中关于WKWebView自适应高度的问题
问题
当webView
作为UITableView
中的tableViewHeader
的时候,因为自身本来就是一个滚动视图,所以为了避免与外部的UITableView
滚动视图冲突,通常的做法都是保证webView
的contentSize
与自身的bounds
的高度保持一直,以保证webView
不会因为内容被隐藏造成自身的内滑动问题。
在保证自身bounds
的高度与contentsize
的高度始终一致的时候,通常的做法就是用kvo
来监听scrollView
的contentsize
属性,然后实时更新当前的frame
的高度。这样的做法是没问题的。但是如果webView
页面中设置了页面的偏移contentInset(偏移值为正值)
的话,则就因为kvo
只更正当前的content
的高度造成偏移的部分被更正削去的问题。
当webView
页面加载完成之后,如果再进行重新reload
的时候,如果reload
的页面高度比之前的高度小,那么由于body.scrollHeight
高度维持之前的页面高度。导致webView
中获取的contentSize
的高度始终为之前页面的高度,导致页面reload
的时候出现大面积空白问题。
总结来说,两个问题:
问题一:在contentSize
里面如果将内容的偏移量在kvo监听中添加的话,会造成页面的死循环,一直循环往复的加高度,原因是因为frame的高度永远大于contentSize
的高度(frame.width = contentSize.width + inset.bottom
),此时会不断的进行叠加(只加不减)
问题二:页面加载完成之后,在进行重新reload
的时候,如果reload
的页面高度比之前的高度少,那么body.scrollHeight
高度维持之前的页面高度。contentSize
高度不变导致页面reload的时候出现大面积空白。
解决
问题一:在
contentSize
里面如果将内容的偏移量在kvo监听中添加的话,会造成页面的死循环,一直循环往复的加高度,原因是因为frame
的高度永远大于contentSize的高度(frame.width = contentSize.width + inset.bottom
),此时会不断的进行叠加
因为在kvo中进行页面的更正,所以inset的偏移量会造成frame高度始终大于contentSize,导致contentSize始终要保持跟frame一致,而cotentSize
变化导致contentView
的height
被间接增加,kvo因此又更新界面bounds
,最终导致循环的产生。
为了避免这个问题,可以通过注入JS的方法间接的去实现页面的偏移。如下:
//添加一个用于偏移的Div的方式达到页面部分内容偏移
//的操作的JS脚本,通过执行JS注入完成页面Inset的效果
NSString *addBrTag = @"var languageView = document.createElement(\"div\");"
"languageView.style.background = \"red\";"
"languageView.style.height=\"44px\";"
"document.body.appendChild(languageView);";
[self evaluateJavaScript:addBrTag completionHandler:^(id _Nullable compelete, NSError * _Nullable error) {
NSLog(@"添加语言切换View的Div执行完毕:%@",error);
}];
问题二:页面加载完成之后,在进行重新
reload
的时候,如果reload
的页面高度比之前的高度少,那么body.scrollHeight
高度维持之前的页面高度。contentSize
高度不变导致页面reload
的时候出现大面积空白。
因为webView的ContentSize
受html
中的body.scrollHeight
影响。重点是在刷新页面的时候通过js重置页面的body.scrollHeight
的高度,可以采取如下做法:
1.去除之前的页面监听(保证重置当前webView
的高度以及内容高度的时候,不会因为kvo
将修改的内容又改回去)
2.重置当前webView
的高度以及内容高度
3.通过JS注入将body
的内容剔除并设置高度为重置的高度
4.注入完成之后,加上kvo监听内容
[weakSelf.scrollView removeObserver:weakSelf forKeyPath:@"contentSize"];
//更新JS中 window.innerHeight
weakSelf.frame = weakSelf.sourceFrame;
weakSelf.scrollView.contentSize = weakSelf.sourceFrame.size;
if(weakSelf.changeFrameBlock){weakSelf.changeFrameBlock(weakSelf.sourceFrame.size.height);};
weakSelf.scrollView.contentOffset = CGPointMake(0, 0);
//更新body.scrollHeight
NSString *updateScrollHeightJS = FormatterStr(@"document.body.innerHTML='';"
"document.getElementsByTagName('body')[0].style.height = %f+'px';",ScreenHeight);
[weakSelf evaluateJavaScript:updateScrollHeightJS completionHandler:^(id _Nullable compelete, NSError * _Nullable error) {
//再次添加kvo
[weakSelf.scrollView addObserver:weakSelf forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];
//刷新页面
[weakSelf reload];
}];
总结
在进行自适应页面高度刷新的时候,有时候也会在页面加载完成之后通过获取页面的body.scrollHeight
来获取页面高度,但是这样在有些时候是不准的,因为有些页面的内容请求是Ajax
异步请求,界面更新在数据加载之前,那会渲染之后的界面与当前更新的页面会有偏差,所以不建议通过这个方法进行页面的更新(尤其是加载一些三方的html页面,不可控),如果是自家的页面,可以与前端小哥商量,通过JS交互
的方法将页面渲染后的高度通过交互给我们,进而刷新页面已获取准确的页面高度。