一、前言

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,相对于UIWebViewWKWebView有着更为强大性能和丰富的API。在项目开发过程中,我也更倾向于用WKWebView,但在使用过程中也遇到许多的问题。

最近接触使用网页视图比较多,自己在tableView和scrollView中嵌套网页视图,在获取网页视图高度遇到过不少的坑,例如高度不准确、底部留白断层,滚动一直获取高度问题。现在项目中使用的网页视图基本都替换成了WKWebView,关于WKWebView使用的一些坑,我强烈推荐一篇博客WKWebView 那些坑,希望使用WKWebView能少走一些弯路,少踩一些坑。好了,话不多说了,我将项目中获取网页视图高度实际经验分享给大家,希望对你有所帮助,下面开始介绍吧!

二、目录

  • 通过KVO的方式
  • 通过代理的方式
  • 通过注入JS的方式,添加网页加载完成回调获取

通过KVO的方式

这种方式获取的高度较为准确,但要注意表格中多次回调高度的问题。

  • 添加监听者

    #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获取网页内容高度,但这种方式不一定就是最真实的高度,这时候可能网页内容还未加载完成,但以实际情况为准。

/**  < 法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代码:

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

然后借助WKWebView代理方法,就能准确获得网页高度:

- (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测试效果。我也贴一个我在项目中添加以上代码片段的位置吧:

<!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>
复制代码

三、问题解决

  • 解决web断层问题:WKWebView刷新机制小探

    #pragma mark ------ < UIScrollViewDeltegate > ------
    - (void)scrollViewDidScroll:(UIScrollView *)scrollView {/**  < 解决web白屏问题 >  *//**  < 需要调用私有API:_updateVisibleContentRects >  */[self.wkWebView setNeedsLayout];
    }
    复制代码

四、demo

最新demo请戳:WKWebViewAutoHeight

五、参考资料

  • ios webview自适应实际内容高度5种方法
  • iOS中webView嵌套tableView中动态高度问题
  • WKWebView刷新机制小探

WKWebView高度自适应三种方式相关推荐

  1. 时序预测的三种方式:统计学模型、机器学习、循环神经网络

    作者 | luanhz 来源 | 小数志 导读 时序预测是一类经典的问题,在学术界和工业界都有着广泛的研究和应用.甚至说,世间万物加上时间维度后都可抽象为时间序列问题,例如股票价格.天气变化等等.关于 ...

  2. JavaScript--------------------jQuery中.bind() .live() .delegate() .on()的区别 和 三种方式写光棒事件 动画...

    bind(type,[data],fn) 为每个匹配元素的特定事件绑定事件处理函数. $("a").bind("click",function(){alert( ...

  3. Spring注解依赖注入的三种方式的优缺点以及优先选择

    当我们在使用依赖注入的时候,通常有三种方式: 1.通过构造器来注入: 2.通过setter方法来注入: 3.通过filed变量来注入: 那么他们有什么区别吗?应该选择哪种方式更好? 代码示例: Con ...

  4. Android录制音频的三种方式

    对于录制音频,Android系统就都自带了一个小小的应用,可是使用起来可能不是特别的灵活.所以有提供了另外的俩种. 下边来介绍下这三种录制的方式; 1.通过Intent调用系统的录音器功能,然后在录制 ...

  5. html布局结构瀑布流,三种方式实现瀑布流布局

    分别使用javascript,jquery,css实现瀑布流布局: 第一种方式:使用JavaScript: 瀑布流布局 *{padding:0;margin:0;} .clearfix:after, ...

  6. Android 音频录制 的三种方式

    对于录制音频,Android系统就都自带了一个小小的应用,可是使用起来可能不是特别的灵活.所以有提供了另外的俩种. 下边来介绍下这三种录制的方式; 1.通过Intent调用系统的录音器功能,然后在录制 ...

  7. Spring依赖注入的三种方式(好的 坏的和丑的)

    关于spring bean三种注入方式的优缺点对比,翻译自Spring DI Patterns: The Good, The Bad, and The Ugly,水平有限,如有错误请指正. Sprin ...

  8. 将div铺满body三种方式

    错误做法 想要令body里一个块元素(div)占全屏,相信很多人(包括我)都会直接把body设置宽高100%,但实际却是,行不通 body{ width:100%; height:100%;} 原因: ...

  9. CSS清除浮动(float)的三种方式

    标题CSS清除浮动(float)的三种方式 为什么要清除浮动? 浮动的原理是让图片脱离文档流,直接浮在画面上.我们一般布局都是只设置宽度不设置高度,让内容来填充高度.但利用浮动后会让原本填充的高度消失 ...

最新文章

  1. shell if else
  2. 高并发下的接口幂等性解决方案!
  3. 自解释的代码根本不存在,老老实实写注释吧
  4. 将ERF格式转换成PCAP格式
  5. php控制变量的显示字数,3.PHP流程控制结构
  6. poj 1860 Currency Exchange (SPFA、正权回路 bellman-ford)
  7. joson返回数据库的时间格式在前台用js转换
  8. empty string什么错误_go语言的interface为什么好用?
  9. 立下2019年的Flag,鞭策自己,使命宣言
  10. 台达plc控制伺服电机编程实例_三菱Q系列PLC控制伺服电机编程实例
  11. 我在淘宝帮别人写代码,月入10万!
  12. 05——去哪儿(旅游网站首页开发)
  13. Appium+python自动化(三十二)- 代码写死一时爽,框架重构火葬场 - PageObject+unittest(超详解)...
  14. ACPC2017游记
  15. 做一个九宫格诗词答题小程序 (二)倒计时功能实现
  16. 无线网络安全工具锦集
  17. 程序员远程斗代码!网页版Skype推出内置实时代码编辑器
  18. 自己都不坚强,又有谁会在意
  19. python实现通讯录管理系统_python练习(通讯管理程序)
  20. React/ReactNative 状态管理: rematch 如何使用

热门文章

  1. linux虚拟单用户数,Linux单用户模式
  2. centos7 ssr一键脚本_RHEL7(Centos7)下使用shell脚本一键部署服务
  3. mysql 类似 user__类似于微博 用户最后一条动态的查询
  4. 计算机信息通信基础知识,计算机基础-(数据通信基础知识)
  5. 大学计算机课英语心得体会,关于计算机网络辅助大学英语教学的思考学习心得...
  6. 穿了个GUI马甲的PyInstaller
  7. 2021年春季学期-信号与系统-第六次作业参考答案-第八小题
  8. 第14期师资培训火热招生中,尽享国赛智能车一手资料
  9. mac文件夹中如何给文件重命名,快捷键是什么
  10. python异常处理类源码_Flask源码异常处理问题