Flutter渲染原理深入解析
Widget Element RenderObject之間的關(guān)系
1 Widget
在Flutter 中,萬物皆是Widget,無論是可見的還是功能型的。一切都是Widget.
官方文檔中說的Widget 使用配置和狀態(tài)來描述View 界面應(yīng)該長什么樣子。
它不僅可以表示UI元素,也可以表示一些功能性的組件如:用于手勢檢測的 GestureDetector、用于APP主題數(shù)據(jù)傳遞的Theme、布局元素等等
兩個(gè)重要的方法
一個(gè)是通過 createElement 來創(chuàng)建 Element 對象的,
一個(gè)是根據(jù) key 來決定更新行為的 canUpdate 方法。
在這個(gè)方法中會(huì)對比runtimeType (也就是widget 的類型)和 key 是否相同
@immutable abstract class Widget extends DiagnosticableTree { /// Initializes [key] for subclasses. const Widget({this.key}); final Key? key; @protected @factory Element createElement(); /// A short, textual description of this widget. @override String toStringShort() { final String type = objectRuntimeType(this, 'Widget'); return key == null ? type : '$type-$key'; } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense; } @override @nonVirtual bool operator ==(Object other) => super == other; @override @nonVirtual int get hashCode => super.hashCode; static bool canUpdate(Widget oldWidget, Widget newWidget) { return oldWidget.runtimeType == newWidget.runtimeType && oldWidget.key == newWidget.key; } // Return a numeric encoding of the specific `Widget` concrete subtype. // This is used in `Element.updateChild` to determine if a hot reload modified the // superclass of a mounted element's configuration. The encoding of each `Widget` // must match the corresponding `Element` encoding in `Element._debugConcreteSubtype`. static int _debugConcreteSubtype(Widget widget) { return widget is StatefulWidget ? 1 : widget is StatelessWidget ? 2 : 0; } }
2 Element
Element 就是一個(gè)Widget 的實(shí)例,在樹中詳細(xì)的位置。
An instantiation of a Widget at a particular location in the tree
3 RenderObject
渲染樹上的一個(gè)對象。負(fù)責(zé)具體布局和繪制這些事情。
4 結(jié)合圖說一下其三者的關(guān)系
從創(chuàng)建到渲染的流程 :
根據(jù)Widget 生成Element,然后創(chuàng)建響應(yīng)的RenderObject并且關(guān)聯(lián)到Element.renderObject 屬性。最后再通過RenderObject 來完成布局和繪制。
依賴關(guān)系:
Element 樹根據(jù)Widget 樹生成,而渲染樹又依賴于widget 樹。
5 一些小問題
widget 和 element 是一一對應(yīng)的嗎 ? 為什么 ?
答:是一一對應(yīng)的。
因?yàn)?abstract class Widget ,本身是一個(gè)抽象類,這個(gè)抽象類中有一個(gè)抽象方法叫做createElement(),子類必須實(shí)現(xiàn)這個(gè)抽象方法,所以是一一對應(yīng)的。
widget 和 renderObject 是一一對應(yīng)的嗎 ? 為什么 ?
答:不是的
因?yàn)橹挥羞@個(gè)widget 繼承自RenderObjectWidget 的時(shí)候,才會(huì)有對應(yīng)的renderObject
像類似 Padding , Row,SizedBox,Center 這種組件繼承自RenderObjectWidget的組件會(huì)有一一對應(yīng)的關(guān)系
//class Padding extends SingleChildRenderObjectWidget // Padding(); // class Flex extends MultiChildRenderObjectWidget // Row()
BuildContext 是什么 ?
答:是Element,不管是StatefulWidget 還是StatelessWidget 都會(huì)重寫父類的build 方法,
build 方法傳入的一個(gè)參數(shù)叫做BuildContext, 我們拿StatelessWidget來說,其本身創(chuàng)建一個(gè)StatelessElement,而在這個(gè)Element內(nèi)部重寫StatelessElement父類的build方法,而在這個(gè)build方法內(nèi)部會(huì)調(diào)用_widget.build 方法,并且把this傳遞進(jìn)去。那么這個(gè)this 就是element 。
/// An [Element] that uses a [StatelessWidget] as its configuration. class StatelessElement extends ComponentElement { /// Creates an element that uses the given widget as its configuration. StatelessElement(StatelessWidget super.widget); @override Widget build() => (widget as StatelessWidget).build(this); @override void update(StatelessWidget newWidget) { super.update(newWidget); assert(widget == newWidget); _dirty = true; rebuild(); } }
Widget 頻繁更改創(chuàng)建是否會(huì)影響性能?復(fù)用和更新機(jī)制是什么樣的?
不會(huì)影響性能,因?yàn)橹皇且恍┡渲眯畔ⅲ瑳]有有布局渲染到頁面上去。中間層Element 會(huì)通過widget 的runtimeType 和 Key 來對比是否進(jìn)行更新操作。
Build 方法會(huì)在什么時(shí)候調(diào)用 ?
Element 創(chuàng)建完畢之后會(huì)調(diào)用mount 方法,對于非渲染的ComponentElement 來說,mount主要執(zhí)行的是Widget 中的build 方法。在StatelessElement 中直接使用的是 widget.build(this),
而在StatefullWidget 方法中,通過的是state.build(this)。在StatefulElement 這個(gè)類中,
初始化列表的給state 進(jìn)行了賦值操作。通過widget調(diào)用createState方法之后,把state賦值給自己的_state 屬性。
StatefulElement(StatefulWidget widget)
: _state = widget.createState(),
createState 方法什么時(shí)候調(diào)用?
答:創(chuàng)建Element 的時(shí)候。
Flutter 會(huì)在遍歷 Widget 樹時(shí)調(diào)用 Widget 里面的 createElement 方法去生成對應(yīng)節(jié)點(diǎn)的 Element 對象,同時(shí)執(zhí)行 StatefulWidget 里面的 createState 方法創(chuàng)建 state,并且賦值給 Element 里的 _state 屬性,當(dāng)前 widget 也同時(shí)賦值給了 state 里的_widget,state 里面有個(gè) widget 的get 方法可以獲取到 _widget 對象。
到此這篇關(guān)于Flutter渲染原理深入解析的文章就介紹到這了,更多相關(guān)Flutter渲染原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
android中webview控件和javascript交互實(shí)例
這篇文章主要介紹了android中webview控件和javascript交互實(shí)例,例子中包括javascript調(diào)用java的方法,java代碼中調(diào)用javascript的方法,需要的朋友可以參考下2014-07-07Android ApplicationContext接口深入分析
ApplicationContext是Spring應(yīng)用程序中的中央接口,由于繼承了多個(gè)組件,使得ApplicationContext擁有了許多Spring的核心功能,如獲取bean組件,注冊監(jiān)聽事件,加載資源文件等2022-11-11Android實(shí)現(xiàn)圓形純數(shù)字按鈕
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)圓形純數(shù)字按鈕,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-02-02Kotlin基礎(chǔ)學(xué)習(xí)之Deprecated與Suppress注解使用
這篇文章主要給大家介紹了關(guān)于Kotlin基礎(chǔ)學(xué)習(xí)之Deprecated與Suppress注解使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Kotlin具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08Android操作Excel文件的功能實(shí)現(xiàn)
本篇文章主要介紹了Android操作Excel文件的功能實(shí)現(xiàn),Android中操作Excel文件導(dǎo)出報(bào)表時(shí)主要采用開源庫jxl,有興趣的可以了解一下。2017-03-03Android string-array數(shù)據(jù)源簡單使用
這篇文章主要介紹了Android string-array數(shù)據(jù)源簡單使用的相關(guān)資料,需要的朋友可以參考下2016-09-09Android基于MLKit實(shí)現(xiàn)條形碼掃碼的代碼示例
這篇文章將借助開源庫?MLKit?實(shí)現(xiàn)條形碼掃描,對于商品條形碼也可以很好地識(shí)別成功,該庫的使用內(nèi)容非常豐富,除了條碼識(shí)別,還有文字識(shí)別、圖像標(biāo)記、人臉檢測等等,本文篇文章就只介紹最基本的條形碼掃描使用,需要的朋友可以參考下2023-08-08Android EditText 實(shí)現(xiàn)監(jiān)聽實(shí)例
本文主要介紹Android EditText 組件 實(shí)現(xiàn)監(jiān)聽事件,并附有代碼實(shí)例,在Android開發(fā)過程中如果能用到可以參考下2016-07-07