Flutter?RendererBinding作用源碼分析
分析
RendererBinding 的作用是負(fù)責(zé)render tree 和flutter engine之間的連接. 我們在啟動(dòng)App的時(shí)候,首先會(huì)創(chuàng)建 PiplineOwner ,然后通過platformDispatcher去監(jiān)聽屏幕分辨率變化、系統(tǒng)文字大小變化、亮度、語義等等.最后去初始化RenderView,根據(jù)平臺去處理如幀回調(diào)、鼠標(biāo)、web之類的信息.
void initInstances() {
super.initInstances();
_instance = this;
_pipelineOwner = PipelineOwner(
onNeedVisualUpdate: ensureVisualUpdate,
onSemanticsOwnerCreated: _handleSemanticsOwnerCreated,
onSemanticsOwnerDisposed: _handleSemanticsOwnerDisposed,
);
platformDispatcher
..onMetricsChanged = handleMetricsChanged
..onTextScaleFactorChanged = handleTextScaleFactorChanged
..onPlatformBrightnessChanged = handlePlatformBrightnessChanged
..onSemanticsEnabledChanged = _handleSemanticsEnabledChanged
..onSemanticsAction = _handleSemanticsAction;
initRenderView();
_handleSemanticsEnabledChanged();
assert(renderView != null);
addPersistentFrameCallback(_handlePersistentFrameCallback);
initMouseTracker();
if (kIsWeb) {
addPostFrameCallback(_handleWebFirstFrame);
}
}
PipelineOwner
這里我們著重講一下PipelineOwner, 官方描述中有這么一句話The pipeline owner manages the rendering pipeline., 也就是說 PipelineOwner幫我們管理著渲染所需要的. 我們根據(jù)PipelineOwner調(diào)用的順序依次講解下它提供的方法.
flushLayout
這個(gè)階段將計(jì)算每個(gè)渲染對象的大小和位置, 渲染對象可能會(huì)在繪制或者compositing state 的時(shí)候被標(biāo)成dirty,這是什么意思呢? 讓我們回歸到代碼中
// 持有需要被布局的對象
List<RenderObject> _nodesNeedingLayout = <RenderObject>[];
{
非release包運(yùn)行代碼忽略
...
try {
// 如果當(dāng)前的節(jié)點(diǎn)需要合成
while (_nodesNeedingLayout.isNotEmpty) {
final List<RenderObject> dirtyNodes = _nodesNeedingLayout;
_nodesNeedingLayout = <RenderObject>[];
for (final RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => a.depth - b.depth)) {
if (node._needsLayout && node.owner == this)
node._layoutWithoutResize();
}
}
} finally {
...
}
}
代碼中可以看到, 如果 _nodesNeedingLayout 中對象不為空.說明當(dāng)前需要被布局,計(jì)算其大小.我們可以看到在依次處理節(jié)點(diǎn)時(shí),最后一步是執(zhí)行 _layoutWithoutResize() ,這個(gè)方法調(diào)用的本質(zhì)實(shí)際上也就是 performLayout(). 那么, performLayout() 做了什么呢? 如果對自定義布局有過了解, 通常我們在實(shí)現(xiàn) performLayout() 的時(shí)候.會(huì)先去 layout widget . 然后去通過position將widget 定位. 確定好widget在父widget中的相對位置.
flushCompositingBits
這個(gè)階段中, 每個(gè)渲染對象都會(huì)了解其子對象是否需要合成.在繪制的階段選擇如何實(shí)現(xiàn)視覺效果. 這里實(shí)際上也就是標(biāo)記所有的子對象是否需要合成
void flushCompositingBits() {
...
_nodesNeedingCompositingBitsUpdate.sort((RenderObject a, RenderObject b) => a.depth - b.depth);
for (final RenderObject node in _nodesNeedingCompositingBitsUpdate) {
if (node._needsCompositingBitsUpdate && node.owner == this)
node._updateCompositingBits();
}
_nodesNeedingCompositingBitsUpdate.clear();
...
}
flushPaint
在這個(gè)階段,我們將會(huì)真正的繪制出Layer
void flushPaint() {
...
try {
final List<RenderObject> dirtyNodes = _nodesNeedingPaint;
_nodesNeedingPaint = <RenderObject>[];
// Sort the dirty nodes in reverse order (deepest first).
for (final RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => b.depth - a.depth)) {
...
if (node._needsPaint && node.owner == this) {
if (node._layerHandle.layer!.attached) {
PaintingContext.repaintCompositedChild(node);
} else {
node._skippedPaintingOnLayer();
}
}
}
...
} finally {
...
}
}
在繪制的時(shí)候?qū)?huì)判斷當(dāng)前的layer是否attached,如果不是attched的狀態(tài).則說明當(dāng)前的layer已經(jīng)調(diào)用detach方法,因此不再需要繪制.所以會(huì)跳過繪制,執(zhí)行 _skippedPaintingOnLayer() 的方法. 如果是attached的狀態(tài),則需要調(diào)用 repaintCompositedChild() 的方法
flushSemantics
最后,如果啟用了語義. 這個(gè)階段將會(huì)編譯渲染對象的語義,這里就不過多介紹了.
initRenderView
如果說還有比較重要的方法需要講解, 那么就是 initRenderView() 這個(gè)方法了.這里將會(huì)創(chuàng)建一個(gè) RenderView的對象作為RenderObject的根 ,同時(shí)對它進(jìn)行初始化.
void initRenderView() {
renderView = RenderView(configuration: createViewConfiguration(), window: window);
// 準(zhǔn)備第一幀啟動(dòng)渲染通道. 這里只會(huì)調(diào)用一次.
renderView.prepareInitialFrame();
}
在 PrepareInitalFrame() 中, 我們通過 scheduleInitialLayout和scheduleInitialPaint , 安排微事務(wù)隊(duì)列盡可能快的處理layout和paint.
scheduleInitialLayout
在這個(gè)階段,主要是將owner的_nodesNeedingLayout 對象中加入這個(gè)初始化的renderview.
scheduleInitialPaint
這個(gè)階段中, 我們將_layerHandle 中的layer 賦值成當(dāng)前l(fā)ayer.并在owner中加入 _nodesNeedingPaint .
void scheduleInitialPaint(ContainerLayer rootLayer) {
_layerHandle.layer = rootLayer;
owner!._nodesNeedingPaint.add(this);
}
今天的RendererBinding源碼分析就暫告一個(gè)段落了,它主要是負(fù)責(zé)了測量布局、繪制之類的方法. 作為一個(gè)入口還是有了解的必要的, 建議大家有時(shí)間可以多看看.
以上就是Flutter RendererBinding作用源碼分析的詳細(xì)內(nèi)容,更多關(guān)于Flutter RendererBinding的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
iOS UIScrollView滾動(dòng)視圖/無限循環(huán)滾動(dòng)/自動(dòng)滾動(dòng)的實(shí)例代碼
這篇文章主要介紹了iOS UIScrollView滾動(dòng)視圖/無限循環(huán)滾動(dòng)/自動(dòng)滾動(dòng),需要的朋友可以參考下2017-02-02
IOS等待時(shí)動(dòng)畫效果的實(shí)現(xiàn)
查詢時(shí)間有長有短,為了增強(qiáng)用戶體驗(yàn)度,目前用的比較多的手段之一是查詢等待時(shí)添加一個(gè)動(dòng)態(tài)等待效果,這篇文章主要介紹IOS等待時(shí)動(dòng)畫效果的實(shí)現(xiàn),有需要的朋友可以參考下2015-08-08
解析iOS應(yīng)用開發(fā)中對設(shè)計(jì)模式中的抽象工廠模式的實(shí)現(xiàn)
這篇文章主要介紹了解析iOS應(yīng)用開發(fā)中對設(shè)計(jì)模式中的抽象工廠模式的實(shí)現(xiàn),示例代碼為傳統(tǒng)的Objective-C,需要的朋友可以參考下2016-03-03
關(guān)于iOS中的各種顏色設(shè)置總結(jié)大全(推薦)
這篇文章主要給大家介紹了關(guān)于iOS中顏色設(shè)置的相關(guān)資料,其中包括導(dǎo)航欄、狀態(tài)欄、Tabbar、Button、TextField、AttributedString和通用部分的顏色設(shè)置方法示例,對大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起看看吧。2017-09-09
IOS開發(fā)中使用writeToFile時(shí)的注意事項(xiàng)
本篇文章主要介紹了開發(fā)中使用writeToFile時(shí)的注意事項(xiàng),具有很好的參考價(jià)值。下面跟著小編一起來看下吧2017-03-03
iOS WKWebView無法處理URL Scheme和App Store鏈接的問題解決
這篇文章主要給大家介紹了關(guān)于iOS WKWebView無法處理URL Scheme和App Store鏈接的問題解決的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-03-03
iOS 輸入驗(yàn)證碼或密碼,自動(dòng)下一位的實(shí)例
下面小編就為大家分享一篇iOS 輸入驗(yàn)證碼或密碼,自動(dòng)下一位的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01

