CSS3 的 -webkit-overflow-scrolling: touch 可以讓頁面在Native端滾動時(shí)模擬原生的彈性滾動效果无蜂。
項(xiàng)目開發(fā)中用到該屬性龙亲,但導(dǎo)致Native端在彈性滾動到邊界時(shí)出現(xiàn)一個(gè)黑色背景的VIEW。
查了一下網(wǎng)上的資料,H5端代碼就不再敷述了,看一下Native處理
-webkit-overflow-scrolling: touch 的流程如下:
實(shí)際上,Safari真的用了原生控件來實(shí)現(xiàn)酥馍,對于有-webkit-overflow-scrolling的網(wǎng)頁,會創(chuàng)建一個(gè)UIScrollView阅酪,提供子layer給渲染模塊使用旨袒。創(chuàng)建時(shí)的堆棧如下:
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
實(shí)際創(chuàng)建的是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
其還有一個(gè)子View作為ContentView峦失,是給WebCore真正用作渲染overflow型內(nèi)容的layer的容器。
UIWebOverflowContentView的聲明為:
@interface UIWebOverflowContentView : UIView{
}
-?(void)_setCachedSubviews:(id)arg1;
-?(void)_replaceLayer:(id)arg1;
-?(void)fixUpViewAfterInsertion;
-?(id)superview;
-?(id)initWithLayer:(id)arg1;
@end
再往底層跟术吗,都是CALayer的操作尉辑。
以上兩個(gè)類都是UIKit層的實(shí)現(xiàn),需要WebCore有硬件加速的支持才有實(shí)際意義较屿,相關(guān)的邏輯被包含在
ACCELERATED_COMPOSITING
這個(gè)宏里隧魄。
從SVN log看卓练,在WebKit 108400版本左右才支持,所以iOS Safari應(yīng)該是需要5.0购啄。Android只在4.0以上支持襟企。
從前端開發(fā)的角度講,只需要知道CSS的屬性-webkit-overflow-scrolling是真的創(chuàng)建了帶有硬件加速的系統(tǒng)級控件狮含,所以效率很高顽悼。但是這相對是耗更多內(nèi)存的,最好在產(chǎn)生了非常大面積的overflow時(shí)才應(yīng)用几迄。
出現(xiàn)黑色背景View其實(shí)就是UIWebOverflowScrollView蔚龙。這個(gè)UIWebOverflowScrollView只有當(dāng)頁面上產(chǎn)生滾動條的時(shí)候才會生成,也就是后加載映胁,所以在模塊運(yùn)行之初去捕捉并設(shè)置這個(gè)VIEW是捕獲不到且不起作用的木羹。
處理思路:
在html端的JS中對滾動條進(jìn)行監(jiān)聽判斷,當(dāng)頁面出現(xiàn)滾動條時(shí)通知Native端解孙。
本人在項(xiàng)目中使用 WebViewJavascriptBridge? 建立H5端與Native端的橋接坑填。Android版本的點(diǎn)這里 。
Native獲取到頁面出現(xiàn)滾動條的通知弛姜,再去捕獲這個(gè)View并修改顏色為白色脐瑰,當(dāng)然顏色是按照你自己的設(shè)計(jì)來修改的,如果本身的APP為黑色娱据,那不改也無妨蚪黑。
代碼如下:
if ([_aView isKindOfClass:[UIScrollView class]])
{
??????? _aView.backgroundColor = [UIColor whiteColor];
??????? //下側(cè)的滾動條
??????? UIView *view = _aView.subviews[0];
??????? for (UIView *_inScrollview in view.subviews)
??????? {
???????????????? NSLog(@"b—%@",_inScrollview);
???????????????? _inScrollview.layer.backgroundColor = [UIColor whiteColor].CGColor;
??????? }
}
最后提一下,由于-webkit-overflow-scrolling: touch對內(nèi)存消耗不小中剩,通知Native的捕獲事件盡量只做一次,節(jié)省開銷抒寂。
資料來源:
網(wǎng)頁在Safari快速滾動和回彈的原理: -webkit-overflow-scrolling : touch;的實(shí)現(xiàn)