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)容會很小棺牧。


圖2.1

為了讓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.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
WKUserScript *wkScript = [[WKUserScript alloc] initWithSource:jsStr injectionTime:WKUserScriptInjectionTimeAtDocumentEnd forMainFrameOnly:YES];
// 添加js調(diào)用
[wkUController addUserScript:wkScript];
WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:webConfig];
圖2.2

如果加載的是HTML代碼,圖片的自適應(yīng)可以通過下面一段CSS代碼來設(shè)置:

NSString *html = @"HTML代碼";
NSString *cssStr = @"<style type=\"text/css\">p{line-height: 24px!important;background-color: #fff;}img{max-width: 100%!important;}</style>";
NSString *htmlStr = [NSString stringWithFormat:@"<!DOCTYPE html><html><head><title>webview</title></head><body>%@%@</body></html>", cssStr, html];
[webView loadHTMLString:htmlStr baseURL:nil];

3.接下來說說重頭戲疲牵,UITableViewCell嵌套WKWebView承二。

(1)cell的高度自適應(yīng)(筆者用的是系統(tǒng)的cell,UITableViewCell)
cell的高度當然是根據(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<NSString *,id> *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"contentSize"]) {

        // 這里有兩種方法獲得webview高度徒溪,第一種就是通過JS代碼來計算出高度忿偷,如下
        // document.documentElement.scrollHeight
        // document.body.offsetHeight
        /*
        [_webView evaluateJavaScript:@"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.reibang.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)化方式不同踊赠,筆者也是在摸索中嘗試著呵扛,如果有說得不對不準確的地方,還請各位指正出來筐带,大家共同探討今穿,互相學習。

代碼下載地址:https://github.com/Nov08/WKWebViewTest

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末伦籍,一起剝皮案震驚了整個濱河市蓝晒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌帖鸦,老刑警劉巖芝薇,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異作儿,居然都是意外死亡洛二,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門攻锰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晾嘶,“玉大人,你說我怎么就攤上這事娶吞±萦兀” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵妒蛇,是天一觀的道長机断。 經(jīng)常有香客問我楷拳,道長,這世上最難降的妖魔是什么吏奸? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任欢揖,我火速辦了婚禮,結(jié)果婚禮上苦丁,老公的妹妹穿的比我還像新娘浸颓。我一直安慰自己,他們只是感情好旺拉,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布产上。 她就那樣靜靜地躺著,像睡著了一般蛾狗。 火紅的嫁衣襯著肌膚如雪晋涣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天沉桌,我揣著相機與錄音谢鹊,去河邊找鬼。 笑死留凭,一個胖子當著我的面吹牛佃扼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蔼夜,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼兼耀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了求冷?” 一聲冷哼從身側(cè)響起瘤运,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎匠题,沒想到半個月后拯坟,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡韭山,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年郁季,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钱磅。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡巩踏,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出续搀,到底是詐尸還是另有隱情,我是刑警寧澤菠净,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布禁舷,位于F島的核電站彪杉,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏牵咙。R本人自食惡果不足惜派近,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望洁桌。 院中可真熱鬧渴丸,春花似錦、人聲如沸另凌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吠谢。三九已至土童,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間工坊,已是汗流浹背献汗。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留王污,地道東北人罢吃。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像昭齐,于是被迫代替她去往敵國和親尿招。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫司浪、插件泊业、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,105評論 4 62
  • 這幾天總是會想起癢癢說的穿越的事,每次想起都笑的不行啊易,所以趕緊記下來吁伺!當時正在看楊冪演的電視劇 老公,你說我要是穿...
    撓撓愛癢癢閱讀 230評論 0 1
  • 譯者:作者講述的這幾個網(wǎng)絡(luò)營銷中的問題租谈,國內(nèi)也屢見不鮮篮奄。分享給大家,一起少走彎路割去。 我討厭看到人們把大把的金錢浪費...
    TsingGuo閱讀 251評論 0 2
  • 文/初見 上學的時候男生總是很不理解呻逆,為什么我們女生上廁所總要成群結(jié)隊的夸赫,是怕掉進廁所沒人打撈起來嗎? 這是因為啊...
    瑪麗蓮懵露閱讀 2,303評論 1 5
  • 送你一片天呼奢,愿你自由翱翔。 送你一片海切平,愿你胸懷坦蕩握础。 送你一片綠,愿你生氣蓬勃悴品。 送你一片心禀综,愿你被愛環(huán)繞。 送...
    喜新亦念舊閱讀 458評論 0 4