wkwebview 下移20像素_UITableView嵌套WKWebView的那些坑
原標(biāo)題:UITableView嵌套WKWebView的那些坑
最近項目中遇到了一個需求,TableView中需要嵌套Web頁面,我的解決辦法是在系統(tǒng)的UITableViewCell中添加WKWebView。開發(fā)的過程中,遇到了些坑,寫出來分享一下。
1.首先說一下WKWebView的代理方法中,頁面加載完成后會走的代理方法,與UIWebView的頁面加載完成代理方法一樣。
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
- (void)webViewDidFinishLoad:(UIWebView *)webView;
這兩個方法都是在web頁面加載完成后才會走的代理方法。什么才算是加載完成呢?web頁面中的所有元素都加載成功,包括圖片、音頻和視頻等資源,都加載成功了,才算加載完成。如果通過這兩個代理方法來計算cell的高度,你的整個tableview頁面就會加載得很慢,至少要等web頁面加載完成后才能計算高度重鋪tableview。
2.WKWebView加載完成展示頁面的時候,會讓整個web頁面自動適應(yīng)屏幕的寬度。這樣展示出來的效果就會很緊湊,頁面內(nèi)容會很小。
為了讓web頁面中的元素都適應(yīng)屏幕的寬度顯示,需要對WKWebView進行一下設(shè)置,原理是加載js代碼,然后通過js來設(shè)置webview中的元素大小:
WKWebViewConfiguration *webConfig = [[WKWebViewConfiguration alloc] init];
WKUserContentController *wkController = [[WKUserContentController alloc] init];
webConfig.userContentController = wkController;
// 自適應(yīng)屏幕寬度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調(diào)用
[wkUController addUser:wk];
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:webConfig];
如果加載的是HTML代碼,圖片的自適應(yīng)可以通過下面一段CSS代碼來設(shè)置:
NSString *html = @"HTML代碼";
NSString *cssStr = @"";
NSString *htmlStr = [NSString stringWithFormat:@"
webview%@%@", cssStr, html];[webView loadHTMLString:htmlStr baseURL:nil];
3.接下來說說重頭戲,UITableViewCell嵌套WKWebView。
(1)cell的高度自適應(yīng)(筆者用的是系統(tǒng)的cell,UITableViewCell)
cell的高度當(dāng)然是根據(jù)webview的高度來設(shè)置的,所以首先要算出webview頁面的高度。開篇就已經(jīng)說過,webview加載完成的代理方法是web頁面中的所有元素都加載成功,包括圖片、音頻和視頻等資源,都加載成功了,才算加載完成。如果頁面中的元素過多,網(wǎng)絡(luò)圖片過大,視頻過大等,就會導(dǎo)致web頁面加載卡頓。本身WKWebView這些資源是異步加載的,但是計算cell高度的時候是在這些資源都加載完成后才計算高度,WKWebView也就失去的異步加載的意義,所以整個tableview都會加載得很慢。
明白了這個道理,我個人推薦使用KVO來代替webview的代理方法。
// 對webView中的scrollView設(shè)置KVO
[_webView.scrollView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:nil];
// KVO具體實現(xiàn)
- (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像素是為了預(yù)留出邊緣,這里可以隨意
CGFloat height = [result doubleValue] + 20;
// 設(shè)置一個高度屬性,賦值后便于設(shè)置cell的高度
_webHeight = height;
// 設(shè)置cell上子視圖的frame,主要是高度
_webView.frame = CGRectMake(0, 0, kScreenWidth, height);
_scrollView.frame = CGRectMake(0, 0, kScreenWidth, height);
_scrollView.contentSize =CGSizeMake(kScreenWidth, height);
// 獲取了高度之后,要更新webview所在的cell,其他的cell就不用更新了,這樣能更節(jié)省資源
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:[NSIndexPath indexPathForRow:1 inSection:0], nil] withRowAnimation:UITableViewRowAnimationNone];
}];
*/
// 第二種方法就是直接使用監(jiān)聽的contentSize.height(這里要感謝[markss](http://www.jianshu.com/u/cc0bd919cb50)簡友的評論提醒),但是與第一種方法不同的就是不能再加多余的高度了,那樣會循環(huán)出發(fā)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"];
}
這樣設(shè)置后的webView直接addSubview到webCell.contentView上,頁面是加載出來了,但是webView的高度并不能改變。
(2)然后筆者百度了一下,找到了一個方法。就是先將webView addSubview到一個scrollView上
[_scrollView addSubview:_webView];
然后再將這個scrollView addSubview到webCell.contentView上
[webCell.contentView addSubview:_scrollView];
這樣webview的高度就可以改變了。但是這是什么原理,筆者還沒搞清楚,希望懂的大神能給予熱情而細心的指導(dǎo)。
(3)在刷新tableview刷新cell的時候,會重新走一遍所有的tableview代理方法,所以筆者建議盡量優(yōu)化- (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;
}
}
總結(jié):
1.在cell上嵌套webview之前,一定要在中間多加一層scrollview。
2.在計算cell高度的時候,不建議直接使用系統(tǒng)webview的代理方法,建議使用kvo。
3.進行減少- (UITableViewCell )tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath方法中對webview的操作,這樣能減少webview的重復(fù)加載,提高性能和速度。
PS:每個人都有自己的想法,每個人的優(yōu)化方式不同,筆者也是在摸索中嘗試著,如果有說得不對不準(zhǔn)確的地方,還請各位指正出來,大家共同探討,互相學(xué)習(xí)。
代碼下載地址:https://github.com/VonKeYuan/WKWebViewTest
作者:天蝎座的Von動必曬
鏈接:http://www.jianshu.com/p/44cfcf0fd538
程序員大咖整理發(fā)布,轉(zhuǎn)載請聯(lián)系作者獲得授權(quán)。返回搜狐,查看更多
責(zé)任編輯:
總結(jié)
以上是生活随笔為你收集整理的wkwebview 下移20像素_UITableView嵌套WKWebView的那些坑的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python点名代码_基于python
- 下一篇: 四种常见的 POST 提交数据方式 专题