iOS開發之UIWebView黑邊的解決方案及淺析

先放上bug演示:

BugShow1

可以看到,在iPhoneX上,網頁加載中會在白底的webView底部出現一塊黑邊,這個就很影響用戶體驗和美觀了,如果加載時間長一點,這個效果就會更加明顯。
BugShow2

經過測試,發現這個問題不只出現在iPhone X及以上機型,其他機型同樣有,只是平時我們網絡很快的話,不去拉就看不到底部的黑邊,實際是存在超過屏幕外的地方
BugShow3(iPhone 8)

那么怎么解決這個問題呢?

解決方案(網上查閱資料得到) :

self.webView.backgroundColor = [UIColor whiteColor];
self.webView.opaque = NO;

好了,如果只是想看這個問題如何解決的話,到這里就可以點左上角或者右上角叉叉關閉了,以下是我對這兩行代碼如何起作用的一些個人分析(扯淡??)。

分析:

為什么這兩行代碼就解決了這個問題呢?是的,一開始我也以為只是iPhone X類機型才會出現的問題,會想用這樣的代碼去解決:

//非完美解決方案
self.webView.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;

這樣是很方便,只一行代碼,iPhone X以上機型不會再出現問題,但同時卻也沒有了底部自動縮進的效果,x類型設備滑到最底部的時候,網頁最底部會緊貼著設備最底部,效果不太好,如果想要自動縮進的話就不方便了。

通過改變scrollView的Behavior屬性為UIScrollViewContentInsetAdjustmentNever
完美解決方案

前者是相當于放棄safeArea自動縮進的功能來實現去黑邊的效果,但是其他非X類機型上任然存在問題,而后面這個才是真正解決了問題,且不影響contentInsetAdjustmentBehavior屬性的使用。
那么這兩行代碼是如何解決這個問題的呢?
我們先來看一下剖析圖

解剖圖

從圖中我們發現UIWebView的結構是UIWebView的子視圖是一個UIWebViewScrollView,然后UIWebViewScrollView上又有一個UIWebBrowserView,就是圖中我選中的View,很明顯黑邊也就是這個東西導致的。

然后我們從opaque入手,從官方文檔上,我們得到這樣的介紹

This property provides a hint to the drawing system as to how it should treat the view. If set to YES, the drawing system treats the view as fully opaque, which allows the drawing system to optimize some drawing operations and improve performance. If set to NO, the drawing system composites the view normally with other content. The default value of this property is YES.

也就是說,如果這個屬性為YES,這個視圖就表現出這個屬性的字面意思,不透明,并且繪圖系統會進行一些優化來提升性能;如果設置為NO,繪圖系統將會把它和其他視圖結合在一起,肯定也不會進行性能優化,所以,這里我們把它關閉,實際上需要它透明,然后不用優化性能。emmm...

???

所以這跟我們實現的效果有什么關聯呢?

好吧,試著去理解一下,是我們這里的webBrowserView導致的問題,那么就從它下手,這里提到透明,難道是把webBrowserView變透明了?嗯?但是我們這里設置opaqueNO的不是webView嗎?說著我嘗試了一下。
因為我是用storyboard做的,webView默認opaqueYES

我們在這里打個斷點

啵一下webView的opaque
可以看到webView只有一個subView
通過剛才的圖層分析,我們知道webBrowserView在webScrollView之上,所以這里啵出webScrollView的subViews,直接找到了我們要的webBrowserView
一步步來,所以這里啵出的就是webBrowserView的opaque屬性

總結一下,正好webViewwebBrowserViewopaque屬性都為YES,好,那我們按照解決方案中說的改為NO試試。

在storyBoard上改為NO

運行起來:
啵一下證明改了

再啵一下webBrowserView的opaque屬性,等等,我發現了什么!

webViewopaque屬性改成NOwebBrowserViewopaque也變成NO了,是不是父視圖的opaque屬性改變會導致相應的子視圖的opaque屬性跟著變化呢?我也去做了一個實驗,結果證明并沒有絕對的關系,大家有興趣可以試試在一個Viewadd另一個view,然后兩個viewopaque設置不同,打斷點,啵出他們的opaque屬性,會發現沒有絲毫影響。

那這里因為webView是系統封裝的一個獨特的視圖,它內部可能有什么不為人知的秘密我這里就只能做個猜測了,如果有懂其中原理的大神還望評論區留言,謝謝啦??!

這里至少證明了webBrowserViewopaque會隨著webViewopaque屬性相應改變。

好,我們執行了第一句webViewopaque設置為NO的代碼,看下效果

效果1

整個webView加載后變成了網頁默認的背景顏色,看下剖析圖:

解剖圖1

webBrowserViewwebView的背景顏色變成一樣了,我們改變一下webView的顏色來證明這個結論:
效果2

解剖圖2

可以看到,將webView背景顏色設為綠色后,webBrowserView的背景也變為綠色了。

OK,那么第二句webView.backgroundColor = [UIColor whiteColor]也可以解釋了,webViewopaque設置為NO后,webBrowser就沒有了黑邊,并且顏色跟webView的背景顏色一樣,之所以要寫成白色,可能大多數需求都是白色吧,所以這里又獲得一個技能,想要設置成啥顏色直接改變webView的背景顏色就可以了,不一定是白色,按照需求來就可以了。

總結:

webViewopaque屬性為YES時,webBrowserViewopaque屬性也為YES,這個時候,webBrowserView不透明,且繪畫系統會對它進行優化,可能認為是直接渲染成白色比較省性能吧,也就是性能優化的結果,而底部的黑邊就是加載網頁的內部控件所留下的效果了(關于webBrowserView內部控件,就觸及到我的盲區了,如果有懂這其中原理的請不吝賜教),總之也是跟性能優化相關;

而將webViewopaque屬性設置為NO時,webBrowserView也會相應的設置opaqueNO(沒有為什么,系統封裝的控件),這個時候繪畫系統就認為webBrowserView是透明的,卻是直接將webBrowserView的顏色設置為webView的顏色,可能是因為webBrowserView要加載并顯示網頁的內容,不能設置成透明的原因吧,所以并沒有讓它透明,而是做了一個類似透明的效果,也就是將背后視圖的顏色設置為自己的顏色(哈哈,你懂得,猜測)。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容