一:Lying人生感悟(可忽略)
摩西奶奶曾經說過:世界上,最公平和最不公平的,都是時間。別人偷不走它。而你也留不住它。你擁有它,卻不能改變它。光陰里的艱難或是快樂,它都一一帶走。身處其中的你我,年輕或是衰老,所能做的,就是充分去享用它,享受每一個生命時期,收藏每一個年齡段帶給你的感動與美好。
是的,這句話我也曾經在某個令人刻骨銘心的夜晚對一個人說過。過去了的事情再提及難免讓人有些懷念。既然走不出來又何必再強求自己走出來。所以讓該來的到來,讓不該走的別走,珍惜所擁有的一切期許是最好的選擇……
二:回到正題(待細看)
故事背景:最近的一次開發中,使用到了overflow:scroll 屬性來滑動div。信心滿滿的以為不會出現任何問題,看來還是太清高自傲了,於是寫下這篇隨筆特此總結一番。
如果你對某個div或模塊使用了overflow: scroll屬性,在iOS系統的手機上瀏覽時,則會出現明顯的卡頓現象。但是在android系統的手機上則不會出現該問題。大家不妨可以分別使用IOS和Android系統的手機瀏覽以下鏈接或掃描二維碼后滑動文字區域查看該效果(重點是記住iPhone瀏覽時的效果,方便瀏覽后文):http://geek100.com/demo/os.html.
表示很奇怪會產生這樣的差異,於是卸下行囊、放下面包、拿出電腦、插上網線、雙擊chrome、在輸入欄中默默地敲上baidu.com...大百度(我更習慣性的稱作為大敗毒,因為它幾乎構成了我學習、工作、生活的全部)。通過一個早上的爬蟲搜索和與前端開發高手的技術探討得知以下代碼可解決這種卡頓的問題:
-webkit-overflow-scrolling: touch;
嗯,這次收拾好心情、重拾之前唾手可棄的信心(不是節操哦)、利用PP助手謹小慎微地把文件拖入iPhone手機中、小心翼翼地點開頁面、手指輕輕在屏幕上滑動...哇哦,果然滑動流暢了誒。來吧!朋友!不妨拿出IPhone一起感受這激動的時刻。鏈接:http://geek100.com/demo/ost.html
據說是因為這行代碼啟用了硬件加速特性,所以滑動很流暢。但是這個屬性也會相對耗費更多內存。在流暢的滑動效果和耗費內存之間,我選擇了前者。
后來深入研究了一下該屬性。具體深入點如下:
實際上,Safari真的用了原生控件來實現,對於有-webkit-overflow-scrolling的網頁,會創建一個UIScrollView,提供子layer給渲染模塊使用。創建時的堆棧如下:
Thread 1, Queue : com.apple.main-thread #0 0x00086723 in -[UIScrollView initWithFrame:] () #1 0x004ec3bd in -[UIWebOverflowScrollView initWithLayer:node:webDocumentView:] () #2 0x001f1769 in -[UIWebDocumentView webView:didCreateOrUpdateScrollingLayer:withContentsLayer:scrollSize:forNode:allowHorizontalScrollbar:allowVerticalScrollbar:] () #3 0x01d571bd in __invoking___ () #4 0x01d570d6 in -[NSInvocation invoke] () #5 0x01d5724a in -[NSInvocation invokeWithTarget:] () #6 0x027fb6a1 in -[_WebSafeForwarder forwardInvocation:] () #7 0x027fb8ab in __44-[_WebSafeAsyncForwarder forwardInvocation:]_block_invoke_0 () #8 0x04ac753f in _dispatch_call_block_and_release () #9 0x04ad9014 in _dispatch_client_callout () #10 0x04ac97d5 in _dispatch_main_queue_callback_4CF () #11 0x01d09af5 in __CFRunLoopRun () #12 0x01d08f44 in CFRunLoopRunSpecific () #13 0x01d08e1b in CFRunLoopRunInMode () #14 0x01cbd7e3 in GSEventRunModal () #15 0x01cbd668 in GSEventRun () #16 0x00032ffc in UIApplicationMain () #17 0x00002ae2 in main at /Users/liuhx/Desktop/UIWebView_Research/WebViewResearch/main.mm:16
實際創建的是UIWebOverflowScrollView,它繼承自UIScrollView,聲明為:
@class DOMNode, UIWebDocumentView, UIWebOverflowContentView, UIWebOverflowScrollListener; @interface UIWebOverflowScrollView : UIScrollView { UIWebDocumentView *_webDocumentView; UIWebOverflowScrollListener *_scrollListener; UIWebOverflowContentView *_overflowContentView; DOMNode *_node; BOOL _beingRemoved; } @property(nonatomic, getter=isBeingRemoved) BOOL beingRemoved; // @synthesize beingRemoved=_beingRemoved; @property(retain, nonatomic) DOMNode *node; // @synthesize node=_node; @property(retain, nonatomic) UIWebOverflowContentView *overflowContentView; // @synthesize overflowContentView=_overflowContentView; @property(retain, nonatomic) UIWebOverflowScrollListener *scrollListener; // @synthesize scrollListener=_scrollListener; @property(nonatomic) UIWebDocumentView *webDocumentView; // @synthesize webDocumentView=_webDocumentView; - (void)setContentOffset:(struct CGPoint)arg1; - (void)_replaceLayer:(id)arg1; - (void)prepareForRemoval; - (void)fixUpViewAfterInsertion; - (id)superview; - (void)dealloc; - (id)initWithLayer:(id)arg1 node:(id)arg2 webDocumentView:(id)arg3; @end
其還有一個子View作為ContentView,是給WebCore真正用作渲染overflow型內容的layer的容器。UIWebOverflowContentView的聲明為:
@interface UIWebOverflowContentView : UIView { } - (void)_setCachedSubviews:(id)arg1; - (void)_replaceLayer:(id)arg1; - (void)fixUpViewAfterInsertion; - (id)superview; - (id)initWithLayer:(id)arg1; @end
再往底層跟,都是CALayer的操作。以上兩個類都是UIKit層的實現,需要WebCore有硬件加速的支持才有實際意義,相關的邏輯被包含在ACCELERATED_COMPOSITING這個宏里。
原理說了一大堆,我表示一句也沒看明白。不過呢,作為知識的分享者就應該要時時刻刻以最簡單明了的說法闡述問題,所以總結以下幾點供大家參考:
-
- 從SVN log看,在WebKit 108400版本左右才支持,所以iOS Safari應該是需要5.0。Android則是在4.0以上支持。
- 從前端開發的角度講,只需要知道CSS的屬性-webkit-overflow-scrolling是真的創建了帶有硬件加速的系統級控件,所以效率很高。
- 從實際開發的角度講,采用這樣的做法相對是耗更多內存的,最好是在產生了非常大面積的overflow時才應用。
三:補充內容(待注意)
- 上述所說的方法的確可以解決ios5.0、android4.0以后系統的滑動卡頓問題,不過呢在這還可以為大家推薦一些相關插件:iScroll(這里是iScroll插件的中文地址)、jRoll(中文名:酸蘿卜) 。
- 關於掌握更多的解決方案或者經驗的朋友不妨在評論下方留言吧。關於閱讀本篇文章的讀者也歡迎你們在評論版里對文章以及本人做出及時的評價與建議。讓我們共同奮進!!!在這向你們表示感謝。
- 在這向文中所提到的前端高人表示真誠感謝。謝謝前輩的耐心解答以及給予的寶貴經驗。同時也感謝前輩在我工作之余的時間里化作暗夜中的一盞明燈,照亮我前行的方向。
- 在這向大家保證該隨筆中的任何一條鏈接都經過嚴格的篩選和把關。100%保證無毒無公害。用伊利純牛奶的廣告語改編后來說則是:百次驗證信賴,見證鏈接品質!(廣告:本隨筆由好喝的不要不要的伊利純牛奶贊助支持......鏈接:https://yili.tmall.com/search.htm)