Widget娜遵、Element、RenderObject 關(guān)系結(jié)構(gòu)分析

序言

使用flutter進(jìn)行開發(fā)也有一段時(shí)間了壤短,今天小轟來聊聊widget设拟、element慨仿、renderObject三者間的結(jié)構(gòu)關(guān)系。

三棵樹

  • Widget 樹負(fù)責(zé)配置信息纳胧,我們平時(shí)寫代碼寫的就是這棵樹镰吆。
  • RenderObject 樹是渲染樹,負(fù)責(zé)計(jì)算布局跑慕,繪制万皿,F(xiàn)lutter 引擎就是根據(jù)這棵樹來進(jìn)行渲染的。
  • Element 樹作為中間者核行,管理著將 Widget 生成 RenderObject和一些更新操作牢硅。


從上圖可以看出,widget 樹和 Element 樹節(jié)點(diǎn)是一一對(duì)應(yīng)關(guān)系钮科,每一個(gè) Widget 都會(huì)有其對(duì)應(yīng)的 Element唤衫。但是 RenderObject 樹則不然,只有需要渲染的 Widget 才會(huì)有對(duì)應(yīng)的節(jié)點(diǎn)绵脯。


Widget

我們平時(shí)用 Widget 使用聲明式的形式寫出來的界面佳励,可以理解為 Widget 樹,這是要介紹的第一棵樹蛆挫。下面赃承,我們來看看 Widget 的結(jié)構(gòu)設(shè)計(jì):

  • widget 分為兩種類型

widget 從渲染的角度進(jìn)行分類,分為 可渲染W(wǎng)idget不可渲染W(wǎng)idget悴侵。像我們常用的 statelessWidget 與 statefulWidget 就屬于不可渲染的Widget瞧剖。

Widget 分類

  • widget 內(nèi)部結(jié)構(gòu)
widget 內(nèi)部成員

如上圖所示:

  1. 每個(gè)widget都提供createElement方法,每個(gè)widget最終都會(huì)轉(zhuǎn)化成Element可免;
  2. widget被觸發(fā)build方法的時(shí)機(jī)特別頻繁抓于,canUpdate方法維護(hù)Element復(fù)用機(jī)制。當(dāng)返回true時(shí)浇借,復(fù)用舊的Element捉撮;
  3. 只有可渲染的widget(子類RenderObjectWidget)提供生成RenderObject的方法

Element

widget的分類相對(duì)應(yīng),element也區(qū)分是否可渲染妇垢,繼承關(guān)系如下:

從上圖中我們得知巾遭,StatefulElement 在其構(gòu)造方法中調(diào)用了 widget.createState 方法,并賦值 _state 其 widget 對(duì)象闯估。
這就是 statefuleWidget createState 方法被調(diào)用的時(shí)機(jī)灼舍。

重點(diǎn):Element 內(nèi)部結(jié)構(gòu)分析
從左往右觀察內(nèi)部成員及方法
整理總結(jié)
  1. Element 持有外部 Widget 對(duì)象。
  2. Element 提供獲取 RenderObject 的方法(get renderObject)涨薪。[從自己開始往子節(jié)點(diǎn)遍歷骑素,直到找出 RenderObjectElement,RenderObjectElement 提供生成RenderObject 的能力]
  3. RenderObjectElement 通過調(diào)用 widget.createRenderObject(this)生成RenderObject
  4. 核心方法 mount()`
  1. componentElement的mount方法主要作用是執(zhí)行build(根據(jù)類型區(qū)分widget.build, state.build
  2. renderObjectElement 的mount方法主要作用是生成RenderObject
  3. Element創(chuàng)建完成時(shí)就會(huì)調(diào)用 mount, 調(diào)用順序?yàn)?mount -> _firstBuild -> reBuild -> performRebuild -> build
  4. Element.markNeedsRebuild 會(huì)重新走 reBuild

RenderObject

RenderObject成員結(jié)構(gòu)
成員方法介紹:
  1. parentData: 由父節(jié)點(diǎn)賦值尤辱,父RenderObj會(huì)將子RenderObj的相關(guān)數(shù)據(jù)存儲(chǔ)在子元素的parentData中砂豌。如在 Stack 布局中厢岂,RenderStack就會(huì)將子元素的偏移數(shù)據(jù)存儲(chǔ)在子元素的parentData中(具體可以查看Positioned實(shí)現(xiàn))。

  2. layout()方法: 接收兩個(gè)參數(shù)阳距,constrains為父節(jié)點(diǎn)對(duì)子節(jié)點(diǎn)的大小限制塔粒;parentUsesSize標(biāo)識(shí)本節(jié)點(diǎn)布局發(fā)生變化時(shí)父節(jié)點(diǎn)是否同步發(fā)生重布局操作。

  3. _relayoutBoundry: 在layout()方法中進(jìn)行賦值筐摘,當(dāng)parentUsesSize等于false時(shí)卒茬,_relayoutBoundry = this(當(dāng)前RenderObject對(duì)象),表示它的大小變化不會(huì)影響到parent的大小咖熟。否則圃酵,_relayoutBoundry = = (parent! as RenderObject)._relayoutBoundary;

  4. markNeedsLayout(): 當(dāng)一個(gè)Element標(biāo)記為 dirty 時(shí)便會(huì)重新 build,這時(shí)RenderObject便會(huì)重新布局馍管,我們是通過調(diào)用 markNeedsBuild() 來標(biāo)記Element為 dirty 的郭赐。

從自身開始向parent遍歷,直到找到是 relayoutBoundry 的 RenderObject 為止确沸。然后將其標(biāo)記為 dirty捌锭,重新build。

void markNeedsLayout() {
   ...省略
   if (_relayoutBoundary != this) {
     markParentNeedsLayout();
   } else {
     ...省略
   }
 }
  1. performResize(): 在layout方法中罗捎,只在sizedByParent 為 true 時(shí)观谦,才會(huì)被調(diào)用。
  2. performLayout(): 在layout方法中被調(diào)用桨菜,每次layout都會(huì)觸發(fā)

題外話豁状,State中setState做了什么?

State.setState() -> _element.markNeedBuild() -> dirty=true -> readerObject.markNeedLayout()

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末倒得,一起剝皮案震驚了整個(gè)濱河市泻红,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌霞掺,老刑警劉巖承桥,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異根悼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蜀撑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門挤巡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人酷麦,你說我怎么就攤上這事矿卑。” “怎么了沃饶?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵母廷,是天一觀的道長(zhǎng)轻黑。 經(jīng)常有香客問我,道長(zhǎng)琴昆,這世上最難降的妖魔是什么氓鄙? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮业舍,結(jié)果婚禮上抖拦,老公的妹妹穿的比我還像新娘。我一直安慰自己舷暮,他們只是感情好态罪,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著下面,像睡著了一般复颈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沥割,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天耗啦,我揣著相機(jī)與錄音,去河邊找鬼驯遇。 笑死芹彬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的叉庐。 我是一名探鬼主播舒帮,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼陡叠!你這毒婦竟也來了玩郊?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤枉阵,失蹤者是張志新(化名)和其女友劉穎译红,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體兴溜,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡侦厚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拙徽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刨沦。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖膘怕,靈堂內(nèi)的尸體忽然破棺而出想诅,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布来破,位于F島的核電站篮灼,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏徘禁。R本人自食惡果不足惜诅诱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望晌坤。 院中可真熱鬧逢艘,春花似錦、人聲如沸骤菠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽商乎。三九已至央拖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鹉戚,已是汗流浹背鲜戒。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留抹凳,地道東北人遏餐。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像赢底,于是被迫代替她去往敵國和親失都。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容