網站首頁 編程語言 正文
分析
RendererBinding 的作用是負責render tree 和flutter engine之間的連接. 我們在啟動App的時候,首先會創建 PiplineOwner ,然后通過platformDispatcher去監聽屏幕分辨率變化、系統文字大小變化、亮度、語義等等.最后去初始化RenderView,根據平臺去處理如幀回調、鼠標、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幫我們管理著渲染所需要的. 我們根據PipelineOwner調用的順序依次講解下它提供的方法.
flushLayout
這個階段將計算每個渲染對象的大小和位置, 渲染對象可能會在繪制或者compositing state 的時候被標成dirty,這是什么意思呢? 讓我們回歸到代碼中
// 持有需要被布局的對象
List<RenderObject> _nodesNeedingLayout = <RenderObject>[];
{
非release包運行代碼忽略
...
try {
// 如果當前的節點需要合成
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 中對象不為空.說明當前需要被布局,計算其大小.我們可以看到在依次處理節點時,最后一步是執行 _layoutWithoutResize() ,這個方法調用的本質實際上也就是 performLayout(). 那么, performLayout() 做了什么呢? 如果對自定義布局有過了解, 通常我們在實現 performLayout() 的時候.會先去 layout widget . 然后去通過position將widget 定位. 確定好widget在父widget中的相對位置.
flushCompositingBits
這個階段中, 每個渲染對象都會了解其子對象是否需要合成.在繪制的階段選擇如何實現視覺效果. 這里實際上也就是標記所有的子對象是否需要合成
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
在這個階段,我們將會真正的繪制出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 {
...
}
}
在繪制的時候將會判斷當前的layer是否attached,如果不是attched的狀態.則說明當前的layer已經調用detach方法,因此不再需要繪制.所以會跳過繪制,執行 _skippedPaintingOnLayer() 的方法. 如果是attached的狀態,則需要調用 repaintCompositedChild() 的方法
flushSemantics
最后,如果啟用了語義. 這個階段將會編譯渲染對象的語義,這里就不過多介紹了.
initRenderView
如果說還有比較重要的方法需要講解, 那么就是 initRenderView() 這個方法了.這里將會創建一個 RenderView的對象作為RenderObject的根 ,同時對它進行初始化.
void initRenderView() {
renderView = RenderView(configuration: createViewConfiguration(), window: window);
// 準備第一幀啟動渲染通道. 這里只會調用一次.
renderView.prepareInitialFrame();
}
在 PrepareInitalFrame() 中, 我們通過 scheduleInitialLayout和scheduleInitialPaint , 安排微事務隊列盡可能快的處理layout和paint.
scheduleInitialLayout
在這個階段,主要是將owner的_nodesNeedingLayout 對象中加入這個初始化的renderview.
scheduleInitialPaint
這個階段中, 我們將_layerHandle 中的layer 賦值成當前layer.并在owner中加入 _nodesNeedingPaint .
void scheduleInitialPaint(ContainerLayer rootLayer) {
_layerHandle.layer = rootLayer;
owner!._nodesNeedingPaint.add(this);
}
今天的RendererBinding源碼分析就暫告一個段落了,它主要是負責了測量布局、繪制之類的方法. 作為一個入口還是有了解的必要的, 建議大家有時間可以多看看.
原文鏈接:https://juejin.cn/post/7171699845634195493
相關推薦
- 2022-11-26 詳解Golang?ProtoBuf的基本語法總結_Golang
- 2022-11-14 react使用useImperativeHandle示例詳解_React
- 2022-12-12 Kotlin?by?lazy關鍵字深入探究實現原理_Android
- 2022-04-30 Django?RestFramework?全局異常處理詳解_python
- 2022-10-05 Android開發Activity毛玻璃背景效果_Android
- 2022-07-09 python處理excel文件之xlsxwriter?模塊_python
- 2022-05-22 Python學習之os包使用教程詳解_python
- 2022-04-20 C++的運算符你真的了解嗎_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支