WKWebView高度自適應三種方式

1、前言

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.javascript

WKWebVIew是iOS8新出的API,旨在替代原有的UIWebView,相對於UIWebViewWKWebView有着更爲強大性能和豐富的API。在項目開發過程當中,我也更傾向於用WKWebView,但在使用過程當中也遇到許多的問題。html

最近接觸使用網頁視圖比較多,本身在tableView和scrollView中嵌套網頁視圖,在獲取網頁視圖高度遇到過很多的坑,例如高度不許確、底部留白斷層,滾動一直獲取高度問題。如今項目中使用的網頁視圖基本都替換成了WKWebView,關於WKWebView使用的一些坑,我強烈推薦一篇博客WKWebView 那些坑,但願使用WKWebView能少走一些彎路,少踩一些坑。好了,話很少說了,我將項目中獲取網頁視圖高度實際經驗分享給你們,但願對你有所幫助,下面開始介紹吧!java

2、目錄

  • 經過KVO的方式
  • 經過代理的方式
  • 經過注入JS的方式,添加網頁加載完成回調獲取

經過KVO的方式

這種方式獲取的高度較爲準確,但要注意表格中屢次回調高度的問題。ios

  • 添加監聽者
    #pragma mark ------ < Private Method > ------
    #pragma mark
    - (void)addWebViewObserver {
        [self.wkWebView.scrollView 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 {
        /**  < 法2 >  */
        /**  < loading:防止滾動一直刷新,出現閃屏 >  */
        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,網頁加載完成經過JS獲取網頁內容高度,但這種方式不必定就是最真實的高度,這時候可能網頁內容還未加載完成,但以實際狀況爲準。git

/**  < 法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的方式,添加網頁加載完成回調獲取

第三種一般是接口返回HTMLString,而後本身在APP客戶端成網頁html、head、body這些標籤,在合適的位置加入如下js代碼:github

<script type=\"text/javascript\">\
        window.onload = function() {\
        window.location.href = \"ready://\" + document.body.scrollHeight;\
        }\
 </script>
複製代碼

而後藉助WKWebView代理方法,就能準確得到網頁高度:web

- (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中是看不到效果的,有興趣的朋友能夠本身拼接網頁HTMLString測試效果。我也貼一個我在項目中添加以上代碼片斷的位置吧:objective-c

<!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>
    
//接口返回網頁內容,拼接在這裏
    
</body>

</html>
複製代碼

3、問題解決

  • 解決web斷層問題:WKWebView刷新機制小探
    #pragma mark ------ < UIScrollViewDeltegate > ------
    - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
        /**  < 解決web白屏問題 >  */
        /**  < 須要調用私有API:_updateVisibleContentRects >  */
        [self.wkWebView setNeedsLayout];
    }
    複製代碼

4、demo

最新demo請戳:WKWebViewAutoHeightapp

5、參考資料

相關文章
相關標籤/搜索