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、参考资料

相关文章
相关标签/搜索