問題描述
最近眼紅WKWebView相對UIWebView的高可配置和高效屯援。在最近的代碼中選擇使用WKWebView來加載JS動態(tài)頁面司倚。但是需要把WebView嵌入到另一個(gè)ScrollView中顯示谎砾,所以需要拉伸到內(nèi)容長度且不能被用戶拖動蕊退。原始代碼如下:
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
[webView evaluateJavaScript:@"document.body.scrollHeight" completionHandler:^(NSNumber *height, NSError * _Nullable error) {
float htmlHeight =[height floatValue];
CGRect webFrame = webView.frame;
webFrame.size.height = htmlHeight;
webView.frame = webFrame;
[self addFeedBackBtn];
}];
}
通過JS代碼得到頁面的高度坪它。
但是這樣的方法對于非靜態(tài)頁面無效营曼,高度并非正確的高度昔案。
解決辦法
編輯于20180813
下面的分割線后是最初始的解決辦法尿贫,但是在部分極端情況下還有用戶反應(yīng)會出現(xiàn)高度持續(xù)增長的問題。
最終找到的原因是WKWebView
的frame
寬度帶有小數(shù)踏揣,而不是整數(shù)庆亡。猜測WKWebView
在計(jì)算contentSize
的時(shí)候是依照frame.width
向下取整的寬度來計(jì)算最終的contentSize
的height
的,然后導(dǎo)致KVO觀察的contentSize高度在更新frame高度后持續(xù)增加捞稿。
更新的解決辦法是對WKWebView的frame寬度求整又谋。
代碼如下_webView.frame = CGRectMake(HWFrame_IPhonePadX(20, 30), height, (NSInteger)(ScreenWidth - HWFrame_IPhonePadX(60, 80)), 0);
。
BTW. 之所以我們的WKWebView
的frame
寬度會帶小數(shù)是因?yàn)槲覀兊?code>HWFrame_IPhonePadX宏會自適應(yīng)屏幕寬高生成輸入數(shù)值對應(yīng)的實(shí)際顯示數(shù)值(這個(gè)數(shù)字是比例計(jì)算而來娱局,會帶有小數(shù)位)彰亥。所以就尷尬了,產(chǎn)生了WKWebView
高度持續(xù)增加的bug衰齐。
初始解決方案
為了監(jiān)控JS動態(tài)頁面的當(dāng)前高度任斋,選擇使用KVO監(jiān)聽WKWebView.scrollView
的contentSize變化。在收到變化通知是耻涛,通過當(dāng)前的contentSize更新webView的frame废酷。代碼如下:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if (object == _webView.scrollView && [keyPath isEqualToString:@"contentSize"]) {
NSLog(@"_webView.scrollView.contentSize %f %f", self.webView.scrollView.contentSize.width, self.webView.scrollView.contentSize.height);
CGRect webFrame = self.webView.frame;
webFrame.size.height = self.webView.scrollView.contentSize.height;
self.webView.frame = webFrame;
}
}
該方法可以基本解決訪問動態(tài)頁面,實(shí)時(shí)更新頁面高度的問題抹缕。
使用KVO記得移除Observer澈蟆,同時(shí)避免過度移除的crash。可以使用下方代碼解決
- (void)removeWebViewObserver {
@try {
if (_webView) {
[_webView.scrollView removeObserver:self forKeyPath:@"contentSize"];
}
}
@catch (NSException *exception) {
NSLog(@"多次刪除kvo 報(bào)錯了");
}
}
偶發(fā)問題
上方方法小概率下會出現(xiàn)監(jiān)聽持續(xù)被觸發(fā)卓研,contentSize.height
持續(xù)不斷增加趴俘,從而使得設(shè)置的frame
的高度也在不斷增加,無限循環(huán)增高鉴分。
我當(dāng)時(shí)工程內(nèi)的表現(xiàn)為高度每次加一哮幢。
解決方案一
通過
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if (object == _webView.scrollView && [keyPath isEqualToString:@"contentSize"]) {
NSLog(@"_webView.scrollView.contentSize %f %f", self.webView.scrollView.contentSize.width, self.webView.scrollView.contentSize.height);
CGRect webFrame = self.webView.frame;
webFrame.size.height = self.webView.scrollView.contentSize.height - 1; // 每次減一可以結(jié)局死循環(huán),持續(xù)增加高度志珍。
self.webView.frame = webFrame;
}
}
該辦法可以解決持續(xù)增加高度的問題橙垢。但是沒有找到根本原因,無法確定所有頁面都是每次加一伦糯,還是有其他可能的情況柜某。所以該方法放棄嗽元。
解決方案二
把WKWebView更換為UIWebView,同樣也通過監(jiān)聽contentSize
來動態(tài)更新webView高度喂击,沒有出現(xiàn)上方的偶發(fā)問題剂癌,高度不會持續(xù)增加。
但是WKWebView比UIWebView更加高效和蘋果更加推薦翰绊,所以也放棄佩谷。
解決方案三
測試代碼,發(fā)現(xiàn)如果不僅僅更新frame的height监嗜,取而代之的通過contentSize同時(shí)更新webView的frame的寬高谐檀,就不會出現(xiàn)高度的持續(xù)增高。但是頁面內(nèi)容寬度會失去限制裁奇,超過webView頁面范圍桐猬。
最終解決方案是通過JS代碼限制webView的內(nèi)容寬度。
方案是不更改監(jiān)聽代碼刽肠,也不對監(jiān)聽得到的高度減一溃肪。更新WKNavigationDelegate的- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
如下:
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
if (webView == _webView) {
NSString *meta = [NSString stringWithFormat:@"document.getElementsByName(\"viewport\")[0].content = \"width=self.webView.frame.size.width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no\""];
[_webView evaluateJavaScript:meta completionHandler:^(id _Nullable complete, NSError * _Nullable error) {
if (complete != nil) {
NSLog(@"complete %@", complete);
} else if (error) {
NSLog(@"error %@", error);
}
}];
}
}
通過強(qiáng)制設(shè)置頁面的寬度為我們當(dāng)前的webView的寬度。解決偶爾出現(xiàn)的高度持續(xù)增加的Bug音五。
Reference
How to determine the content size of a UIWebView?
iOS 修改webView字體大小,設(shè)置寬度及縮放效果