一、前言
Important
Starting in iOS 8.0 and OS X 10.10, use WKWebView to add web content to your app. Do not use UIWebView or WebView.
WKWebVIew是iOS8新出的API,旨在替代原有的UIWebView,相對(duì)于UIWebView,WKWebView有著更為強(qiáng)大性能和豐富的API。在項(xiàng)目開發(fā)過程中,我也更傾向于用WKWebView,但在使用過程中也遇到許多的問題。
最近接觸使用網(wǎng)頁視圖比較多,自己在tableView和scrollView中嵌套網(wǎng)頁視圖,在獲取網(wǎng)頁視圖高度遇到過不少的坑,例如高度不準(zhǔn)確、底部留白斷層,滾動(dòng)一直獲取高度問題?,F(xiàn)在項(xiàng)目中使用的網(wǎng)頁視圖基本都替換成了WKWebView,關(guān)于WKWebView使用的一些坑,我強(qiáng)烈推薦一篇博客WKWebView 那些坑,希望使用WKWebView能少走一些彎路,少踩一些坑。好了,話不多說了,我將項(xiàng)目中獲取網(wǎng)頁視圖高度實(shí)際經(jīng)驗(yàn)分享給大家,希望對(duì)你有所幫助,下面開始介紹吧!
二、目錄
- 通過KVO的方式
- 通過代理的方式
- 通過注入JS的方式,添加網(wǎng)頁加載完成回調(diào)獲取
通過KVO的方式
這種方式獲取的高度較為準(zhǔn)確,但要注意表格中多次回調(diào)高度的問題。
- 添加監(jiān)聽者
#pragma mark ------ < Private Method > ------ #pragma mark - (void)addWebViewObserver { [self.wkWebView.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil]; } - 監(jiān)聽高度變化
#pragma mark ------ < KVO > ------ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context { /** < 法2 > */ /** < loading:防止?jié)L動(dòng)一直刷新,出現(xiàn)閃屏 > */ if ([keyPath isEqualToString:@"contentSize"]) { CGRect webFrame = self.wkWebView.frame; webFrame.size.height = self.wkWebView.scrollView.contentSize.height; self.wkWebView.frame = webFrame; [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:[NSIndexPath indexPathForRow:3 inSection:0], nil] withRowAnimation:UITableViewRowAnimationNone]; } } - 移除觀察者
- (void)removeWebViewObserver { [self.wkWebView.scrollView removeObserver:self forKeyPath:@"contentSize"]; }
通過代理的方式
這種方法通過WKNavigationDelegate代理方法- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation,網(wǎng)頁加載完成通過JS獲取網(wǎng)頁內(nèi)容高度,但這種方式不一定就是最真實(shí)的高度,這時(shí)候可能網(wǎng)頁內(nèi)容還未加載完成,但以實(shí)際情況為準(zhǔn)。
/** < 法2 > */
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
//document.body.offsetHeight
//document.body.scrollHeight
//document.body.clientHeight
[webView evaluateJavaScript:@"document.body.offsetHeight" completionHandler:^(id _Nullable result, NSError * _Nullable error) {
CGFloat documentHeight = [result doubleValue];
CGRect webFrame = webView.frame;
webFrame.size.height = documentHeight;
webView.frame = webFrame;
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:[NSIndexPath indexPathForRow:3 inSection:0], nil] withRowAnimation:UITableViewRowAnimationNone];
}];
// CGRect webFrame = self.wkWebView.frame;
// CGFloat contentHeight = webView.scrollView.contentSize.height;
// webFrame.size.height = contentHeight;
// webView.frame = webFrame;
// [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:[NSIndexPath indexPathForRow:3 inSection:0], nil] withRowAnimation:UITableViewRowAnimationNone];
}
通過注入JS的方式,添加網(wǎng)頁加載完成回調(diào)獲取
第三種通常是接口返回HTMLString,然后自己在APP客戶端成網(wǎng)頁html、head、body這些標(biāo)簽,在合適的位置加入以下js代碼:
<script type=\"text/javascript\">\
window.onload = function() {\
window.location.href = \"ready://\" + document.body.scrollHeight;\
}\
</script>
然后借助WKWebView代理方法,就能準(zhǔn)確獲得網(wǎng)頁高度:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
if (navigationAction.navigationType == WKNavigationTypeOther) {
if ([[[navigationAction.request URL] scheme] isEqualToString:@"ready"]) {
float contentHeight = [[[navigationAction.request URL] host] floatValue];
CGRect webFrame = self.wkWebView.frame;
webFrame.size.height = contentHeight;
webView.frame = webFrame;
NSLog(@"onload = %f",contentHeight);
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:[NSIndexPath indexPathForRow:3 inSection:0], nil] withRowAnimation:UITableViewRowAnimationNone];
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
}
decisionHandler(WKNavigationActionPolicyAllow);
}
第三種方法在我寫的demo中是看不到效果的,有興趣的朋友可以自己拼接網(wǎng)頁HTMLString測試效果。我也貼一個(gè)我在項(xiàng)目中添加以上代碼片段的位置吧:
<!DOCTYPE html>
<html>
<meta charset=\"utf-8\">
<meta name=\"viewport\"content=\"width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\">\
<title></title>
<head>
<script type=\"text/javascript\">\
window.onload = function() {\
window.location.href = \"ready://\" + document.body.scrollHeight;\
}\
</script>
</head>
<body>
//接口返回網(wǎng)頁內(nèi)容,拼接在這里
</body>
</html>
三、問題解決
- 解決web斷層問題:WKWebView刷新機(jī)制小探
#pragma mark ------ < UIScrollViewDeltegate > ------ - (void)scrollViewDidScroll:(UIScrollView *)scrollView { /** < 解決web白屏問題 > */ /** < 需要調(diào)用私有API:_updateVisibleContentRects > */ [self.wkWebView setNeedsLayout]; }
四、demo
最新demo請(qǐng)戳:WKWebViewAutoHeight