原标题:UITableView嵌套WKWebView的那些坑

最近项目中遇到了一个需求,TableView中需要嵌套Web页面,我的解决办法是在系统的UITableViewCell中添加WKWebView。开发的过程中,遇到了些坑,写出来分享一下。

1.首先说一下WKWebView的代理方法中,页面加载完成后会走的代理方法,与UIWebView的页面加载完成代理方法一样。

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation

- (void)webViewDidFinishLoad:(UIWebView *)webView;

这两个方法都是在web页面加载完成后才会走的代理方法。什么才算是加载完成呢?web页面中的所有元素都加载成功,包括图片、音频和视频等资源,都加载成功了,才算加载完成。如果通过这两个代理方法来计算cell的高度,你的整个tableview页面就会加载得很慢,至少要等web页面加载完成后才能计算高度重铺tableview。

2.WKWebView加载完成展示页面的时候,会让整个web页面自动适应屏幕的宽度。这样展示出来的效果就会很紧凑,页面内容会很小。

为了让web页面中的元素都适应屏幕的宽度显示,需要对WKWebView进行一下设置,原理是加载js代码,然后通过js来设置webview中的元素大小:

WKWebViewConfiguration *webConfig = [[WKWebViewConfiguration alloc] init];

WKUserContentController *wkController = [[WKUserContentController alloc] init];

webConfig.userContentController = wkController;

// 自适应屏幕宽度js

NSString *jsStr = @"var meta = document.('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].(meta);";

WKUser *wk = [[WKUser alloc] initWithSource:jsStr injectionTime:WKUserInjectionTimeAtDocumentEnd forMainFrameOnly:YES];

// 添加js调用

[wkUController addUser:wk];

WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:webConfig];

如果加载的是HTML代码,图片的自适应可以通过下面一段CSS代码来设置:

NSString *html = @"HTML代码";

NSString *cssStr = @"";

NSString *htmlStr = [NSString stringWithFormat:@"

webview%@%@", cssStr, html];

[webView loadHTMLString:htmlStr baseURL:nil];

3.接下来说说重头戏,UITableViewCell嵌套WKWebView。

(1)cell的高度自适应(笔者用的是系统的cell,UITableViewCell)

cell的高度当然是根据webview的高度来设置的,所以首先要算出webview页面的高度。开篇就已经说过,webview加载完成的代理方法是web页面中的所有元素都加载成功,包括图片、音频和视频等资源,都加载成功了,才算加载完成。如果页面中的元素过多,网络图片过大,视频过大等,就会导致web页面加载卡顿。本身WKWebView这些资源是异步加载的,但是计算cell高度的时候是在这些资源都加载完成后才计算高度,WKWebView也就失去的异步加载的意义,所以整个tableview都会加载得很慢。

明白了这个道理,我个人推荐使用KVO来代替webview的代理方法。

// 对webView中的scrollView设置KVO

[_webView.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];

// KVO具体实现

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context

{

if ([keyPath isEqualToString:@"contentSize"]) {

// 这里有两种方法获得webview高度,第一种就是通过JS代码来计算出高度,如下

// document.documentElement.scrollHeight

// document.body.offsetHeight

/*

[_webView evaluateJava:@"document.body.offsetHeight" completionHandler:^(id _Nullable result, NSError * _Nullable error) {

// 加20像素是为了预留出边缘,这里可以随意

CGFloat height = [result doubleValue] + 20;

// 设置一个高度属性,赋值后便于设置cell的高度

_webHeight = height;

// 设置cell上子视图的frame,主要是高度

_webView.frame = CGRectMake(0, 0, kScreenWidth, height);

_scrollView.frame = CGRectMake(0, 0, kScreenWidth, height);

_scrollView.contentSize =CGSizeMake(kScreenWidth, height);

// 获取了高度之后,要更新webview所在的cell,其他的cell就不用更新了,这样能更节省资源

[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:[NSIndexPath indexPathForRow:1 inSection:0], nil] withRowAnimation:UITableViewRowAnimationNone];

}];

*/

// 第二种方法就是直接使用监听的contentSize.height(这里要感谢[markss](http://www.jianshu.com/u/cc0bd919cb50)简友的评论提醒),但是与第一种方法不同的就是不能再加多余的高度了,那样会循环出发KVO,不断的增加高度直到crash。

UIScrollView *scrollView = (UIScrollView *)object;

CGFloat height = scrollView.contentSize.height;

_webHeight = height;

_webView.frame = CGRectMake(0, 0, kScreenWidth, height);

_scrollView.frame = CGRectMake(0, 0, kScreenWidth, height);

_scrollView.contentSize =CGSizeMake(kScreenWidth, height);

[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:[NSIndexPath indexPathForRow:1 inSection:0], nil] withRowAnimation:UITableViewRowAnimationNone];

}

}

// 别忘注销kvo

- (void)dealloc

{

[_webView.scrollView removeObserver:self forKeyPath:@"contentSize"];

}

这样设置后的webView直接addSubview到webCell.contentView上,页面是加载出来了,但是webView的高度并不能改变。

(2)然后笔者百度了一下,找到了一个方法。就是先将webView addSubview到一个scrollView上

[_scrollView addSubview:_webView];

然后再将这个scrollView addSubview到webCell.contentView上

[webCell.contentView addSubview:_scrollView];

这样webview的高度就可以改变了。但是这是什么原理,笔者还没搞清楚,希望懂的大神能给予热情而细心的指导。

(3)在刷新tableview刷新cell的时候,会重新走一遍所有的tableview代理方法,所以笔者建议尽量优化- (UITableViewCell )tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath中的代码,防止多次加载webview

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

switch (indexPath.row) {

case 0:

{

ArticleHeaderTableViewCell *articleHeaderCell = [tableView dequeueReusableCellWithIdentifier:_articleHeaderIdentifier forIndexPath:indexPath];

return articleHeaderCell;

}

break;

case 1:

{

// 嵌套webivew的cell

UITableViewCell *webCell = [tableView dequeueReusableCellWithIdentifier:_articleWebIdentifier forIndexPath:indexPath];

[webCell.contentView addSubview:_scrollView];

return webCell;

}

break;

case 2:

{

ArticleCommentTableViewCell *articleCommentCell = [tableView dequeueReusableCellWithIdentifier:_articleCommentIdentifier forIndexPath:indexPath];

return articleCommentCell;

}

break;

default:

{

CommentsTableViewCell *commentsCell = [tableView dequeueReusableCellWithIdentifier:_commentsIdentifier forIndexPath:indexPath];

return commentsCell;

}

break;

}

}

总结:

1.在cell上嵌套webview之前,一定要在中间多加一层scrollview。

2.在计算cell高度的时候,不建议直接使用系统webview的代理方法,建议使用kvo。

3.进行减少- (UITableViewCell )tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath方法中对webview的操作,这样能减少webview的重复加载,提高性能和速度。

PS:每个人都有自己的想法,每个人的优化方式不同,笔者也是在摸索中尝试着,如果有说得不对不准确的地方,还请各位指正出来,大家共同探讨,互相学习。

代码下载地址:https://github.com/VonKeYuan/WKWebViewTest

作者:天蝎座的Von动必晒

链接:http://www.jianshu.com/p/44cfcf0fd538

程序员大咖整理发布,转载请联系作者获得授权。返回搜狐,查看更多

责任编辑:

wkwebview 下移20像素_UITableView嵌套WKWebView的那些坑相关推荐

  1. UITableView嵌套WKWebView的那些坑

    最近项目中遇到了一个需求,TableView中需要嵌套Web页面,我的解决办法是在系统的UITableViewCell中添加WKWebView.开发的过程中,遇到了些坑,写出来分享一下. 1.首先说一 ...

  2. 关于xcode5 下调试 ios7 系统 界面上移20像素 解决

    记得在 苹果 6月份 出 ios7系统 的beta版本时, 当时因为新鲜,就第一时间升级到了 ios7系统. 结果发现 xcode 4.6 不识别ios7系统,于是 就下载了,xcode5 的预览版. ...

  3. ios wkwebview弹框_iOS 加载WKWebView

    WKWebView是苹果在iOS 8之后推出的框架WebKit中的浏览器控件, 其加载速度比UIWebView快了许多, 但内存占用率却下降很多, 也解决了加载网页时的内存泄露问题. WKWebVie ...

  4. wkwebview替换uiwebview_UIWebView完美切换至WKWebView

    UIWebView完美切换至WKWebView发布日期:2018-6-10 来源:csdn [关闭] iOS8之后,苹果推出了WebKit这个框架,用来替换原有的UIWebView,新的控件优点多多, ...

  5. 包括 一个 20像素的黑条条

    SharedAppDelegate.window.frame.size.height 转载于:https://www.cnblogs.com/guligei/p/3248448.html

  6. 江南大学计算机专业考研压分吗,考研专业课压分,不保护一志愿考生?20考研的我该如何避坑?...

    俗话说得好:"报考一时爽,录取火葬场",不管是现在2020考研还是2021考研的考生,在院校专业选择的时候避免一些坑还是很重要的,选择不对,分数在考得再高也可能被刷,甚至连调剂的机 ...

  7. ScrollView嵌套WebView遇到的坑

    最近遇到一个问题,在项目中ScrollView嵌套了WebView,点击WebView后会向上自动滑动,查看了原因发现是因为WebView优先获取了焦点,导致点击WebView引起的滑动,只需要在We ...

  8. ubuntu 20.04 配置ITS环境遇到的坑

    1.ubuntu默认有python3,但是我们测试需要python2的环境 https://segmentfault.com/a/1190000022572643 sudo apt install p ...

  9. Android之SwipeRefreshLayout嵌套RecyclerView遇到的坑

    1 .需求 RecyclerView多布局里面加入SwipeRefreshLayout实现下拉刷新 2.关键代码 <androidx.swiperefreshlayout.widget.Swip ...

最新文章

  1. Matlab中的图形句柄(转载)
  2. 基于Spark ML 聚类分析实战的KMeans
  3. LetCode 3 无重复字符的最大子串
  4. 分析函数RANK的使用
  5. python特定词频统计_词频统计方案与具体实现-elasticsearch、spark、python
  6. linux shell 基本规范
  7. 记HTML5 a 标签的一个小坑 1
  8. 初学者参考C#中操作XML修改完整版
  9. 破解金山ocr文字识别软件
  10. vue 音乐播放器之歌词解析和滚动(js源码)
  11. html图片表情怎么搞,学习使用HTML5/CSS3来制作简单的表情动画
  12. oracle 如何锁定表,oracle中表的锁定
  13. UBUNTU 7.04安装后的配置
  14. VT是什么?怎么打开教程
  15. 微信小游戏排行榜卡顿或无法滑动
  16. 模拟电路50(开关电容滤波器)
  17. 14个令人惊叹的Ionic应用程序模板
  18. 费雪MOGAFX方程式是什么?(二) -
  19. 【快乐摸鱼】— 用python开发益智游戏
  20. 实验1 进程管理实验-计算机操作系统

热门文章

  1. 如何确定JTAG好坏?JTAG到底是什么?
  2. bash 2_quantize.sh遇到错误2_quantize.sh: line 7: 29380 Segmentation fault解决方法
  3. python验证码识别接口 服务器_python验证码识别模块
  4. 逆置单链表c语言程序,(数据结构C语言版)顺序表和单链表的逆置
  5. java实现jsonscheme_java – jsonschema和日期类型
  6. python创建数据库的sql语句_对python插入数据库和生成插入sql的示例讲解
  7. vue商城源码_一个标星 5.2k+ 的牛逼开源商城系统
  8. python列表元组字符串都属于有序数列_列表、元组、字符串是Python的__________(有序、无序?)序列。...
  9. PhotoShop更改图片背景色
  10. jmeter的几种参数化使用方法