摘要:著急要解決方案腾啥,直接滾到結(jié)尾復(fù)制有效代碼秸应,即可。本文記錄了本人在解決這個過程的大致心路歷程碑宴,可以說是摸索的過程吧软啼。拙筆耕耘,謝謝閱讀延柠。
最近在項目中祸挪,遇到一個棘手的問題:webView裝載H5頁面,設(shè)置導(dǎo)航欄顏色和h5頁面保持一致的情況下贞间,下拉h(huán)5頁面頂部會產(chǎn)生一個視覺斷層贿条,這對用戶并不友好。于是開始了一系列的探索之路增热。
最初嘗試的解決方式:
設(shè)置WKWebView下的scrollView的屬性
webView.scrollView.bounces =false
// default NO. if YES and bounces is YES, even if content is smaller than bounds, allow drag vertically
webView.scrollView.alwaysBounceVertical = false //其實默認(rèn)也是false
但簡單的設(shè)置并不起作用整以。
于是從渲染層的效果看當(dāng)前的視圖層次,仔細(xì)扒拉發(fā)現(xiàn)當(dāng)前的渲染視圖層次里最上層裝載h5內(nèi)容的是一個WKChildScrollView 峻仇,這就tm的搞笑公黑,是我漲了見識也是技術(shù)迭代的快啊,繼續(xù)探索,下意識就是既然我可以看到這個視圖凡蚜,那就可以拿到這個對象進行操作人断。只能說幼稚坦然暴露在在未知領(lǐng)域的面前,且即便有著龐大的數(shù)量基數(shù)朝蜘。接下來恶迈,我通過webView.scrollView.subviews[0].subviews[0].subviews[0].subviews[0]這種方式獲取了5-6層的子View并且遍歷,然后并沒有拿到谱醇。打破了以前的這種求知路線的經(jīng)驗暇仲。
接下來,向另一個路線尋找解決方案副渴,從js代碼上入手熔吗,以前的工作經(jīng)驗告訴我,webview是可以獲取到h5的上下文(JSContext)佳晶,再通過“deocment.xxx.xxx...”獲取H5內(nèi)部控件元素。于是開啟了更多偏向js層面與原生交互的學(xué)習(xí)探索讼载,進行猛烈的炮火攻擊轿秧,搜羅了市面的大多數(shù)webView與js的中文文章(少量的類似問題的英文文檔),在不斷加深對webview的理解中咨堤,我有一個深刻意識菇篡,可以用js解決了這個問題。
果然搜到了很多解決方案一喘,例如解決H5頁面在iOS系統(tǒng)中滑動回彈效果(橡皮筋效果)導(dǎo)致的穿透問題此類眾多驱还,或者集成一個貌似叫bounce的js庫解決,就是需要前端做集成修改的方案凸克,然而事實證明议蟆,還在路上。繼續(xù)gank萎战,終于咐容,emmmm,上代碼
document.body.addEventListener('touchmove', function (e) {
e.preventDefault();
}, {passive: false});
效果很明顯蚂维,就是h5頁面直接不能滑動戳粒。心里獨白就是這....就離譜。標(biāo)題打著已經(jīng)解決的旗號虫啥,結(jié)果是醫(yī)駝不蔽翟迹活的方案。讓我想起草原上飛奔的草泥馬涂籽,默默的一句“啊苹祟,呸”。
然后,繼續(xù)往JSValue這種線上摸苔咪,線太長锰悼,精力有限,消耗原動力沒有產(chǎn)出团赏,于是放棄了(識得前景大箕般,不因一隅陷啊)舔清。主要是找了前端交流探討丝里,加上前面的經(jīng)驗,我下意識回到了WKWebView的本身体谒,
然后又在一個微信iOS群里拋出了這個問題杯聚,有伙伴,給出了以下的解決方案:
let firstTempList:[UIView] = webView.scrollView.subviews
let subTempList = firstTempList.first?.subviews ?? []
subTempList.first?.backgroundColor = UIColor.grayF8()
copy+v+c之后抒痒,無法獲直接取的view顏色倒是可以設(shè)置幌绍,但還是不能,又加上了
webView.scrollView.isOpaque = true
個人測試是不能通過實現(xiàn)設(shè)置底色的方式故响,消去視覺斷層的問題的傀广,但還是建議遇到類似問題嘗試下。
在上述依然不能解決問題的前提下彩届,我想這就是寫博客的機會了(裝了裝了伪冰,就是感覺這樣的問題,解決方式不應(yīng)該沒有以及應(yīng)該說不上會很難樟蠕,所以堅持繼續(xù)探究的贮聂,一開始沒有想到寫此文章,真有文章解決寨辩,我是沒心浪費精力寫的)吓懈。
到這里,也是過了一些時間了靡狞,牽強附會的扯上初心吧骄瓣,又回到了當(dāng)初的獲取WKChildScrollView的方式。不甘心的又使用了webView.scrollView.subviews[0].subviews[0].subviews[0].subviews[0]這種方式耍攘,在未知的領(lǐng)域面前榕栏,幼稚不分對象。但是不甘讓人產(chǎn)生堅持心蕾各,于是我決定把subview子類鏈走到底扒磁,慶幸每個subviews- item并不多啊,終于式曲,終于妨托,看下圖:(不要著急懵逼和嘆服取了足足10層)
于是缸榛,終于看到晨曦的光,于是進行了下面的操作
事情進行到這兰伤,終于松了一口氣内颗。目的地是已到達,但多少還是跟完美有點距離敦腔。因為iOS的系統(tǒng)版本不斷更新均澳,這個解決方式只能算是解決了當(dāng)前版本的當(dāng)下場景的問題。而且符衔,這樣的代碼作為上線代碼找前,顯然不行滴。直接強解包讀取危害太大判族,用fisrt或last替換也是太low躺盛,而且不能兼容各種場景。于是嘗試while循環(huán)形帮,條件是subview.count > 0槽惫。 所以gank,寫了幾句代碼辩撑,這......還不如來個遞歸吧界斜。于是我的終極解決方案出來了,如下槐臀。(有一個缺點是所有的WebView的頁面的下拉的彈簧效果都被禁止了,稍后給出解決方案)
func checkSubviewsIsContoinScrollView(v: UIView?) {
v?.subviews.forEach({ itemV in
if itemV.isKind(of: UIScrollView.**self**), **let** childScrollV = itemV as? UIScrollView {
childScrollV.bounces = **false**
}
self.checkSubviewsIsContoinScrollView(v: itemV)
})
}
//調(diào)用的地方以及逐漸優(yōu)化
checkSubviewsIsContoinScrollView(v: webView)
// let childScrollView = webView.scrollView.subviews[0].subviews[0].subviews[0].subviews[0].subviews[0].subviews[0].subviews[1].subviews[0].subviews[0].subviews[0]
// let WKChildScrollView: AnyClass? = NSClassFromString("WKChildScrollView")
// if let WKChildScrollView = WKChildScrollView, childScrollView.isKind(of: WKChildScrollView.self) {
// if let childScrollV = childScrollView as? UIScrollView {
// childScrollV.bounces = false
// }
// }
// if childScrollView.isKind(of: UIScrollView.self) {
// if let childScrollV = childScrollView as? UIScrollView {
// childScrollV.bounces = false
// }
// }
致此氓仲,方是柳暗花明又一村啊水慨。
缺點一: 就是所有裝載的h5頁面的頂部彈簧效果都被禁了,這其實不友好敬扛。
解決方案一:寫一個BaseWebViewVC不實現(xiàn)上面的代碼晰洒,然后再繼承BaseWebViewVC寫一個BaseNoBounceWebViewVC,實現(xiàn)上述代碼啥箭。
解決方案二:可以直接通過獲取當(dāng)前導(dǎo)航欄是否有顏色谍珊,再結(jié)合js代碼獲取當(dāng)前h5頁面是否有背景的場景來判斷是否調(diào)用上述方法。
缺點二:
本人測試的存在數(shù)據(jù)加載緩慢的情況急侥,而這段代碼并不工作(概率極小砌滞,但還需要優(yōu)化)。推測是因為數(shù)據(jù)加載緩慢導(dǎo)致視圖層次渲染延遲坏怪,在viewDidAppear中贝润,WKChildScrollView還沒有渲染生成的原因。期待大神給出這個的優(yōu)化的方案铝宵。
//有嘗試在此方法中調(diào)用打掘,但是沒有效果华畏,同時進行延遲幾秒的調(diào)用有生效,那基本就閉環(huán)解決了尊蚁。因為測試 case量少亡笑,不能保證。
func webView(webView: WKWebView, didFinish navigation: WKNavigation!)