Flutter中Widget與Element關係

2021-10-05 07:12:41 字數 4408 閱讀 2507

widget

widget 是 flutter 世界裡對檢視的一種結構化描述,你可以把它看作是前端中的「控制項」或「元件」。widget 是控制項實現的基本邏輯單位,裡面儲存的是有關檢視渲染的配置資訊,包括布局、渲染屬性、事件響應資訊等。

實際上,flutter 種真正代表螢幕上顯示元素的類時element,widget 只是描述 element 的配置資料,並且乙個widget 可以對應多個element。

另外,由於 widget 的不可變性,可以以較低成本進行渲染節點復用,因此在乙個真實的渲染樹中可能存在不同的 widget 對應同乙個渲染節點的情況,這無疑又降低了重建 ui 的成本。

//widget 類繼承自 diagnosticabletree ,diagnosticabletree為「診斷樹」,主要作用是提供除錯資訊

abstract class widget extends diagnosticabletree );

//key,類似於 react/vue 中的key,主要的作用是決定是否在下一次建立時復用舊的 widget ,條件在canupdate方法中

final key key;

//flutter framework在構建ui樹時,會先呼叫此方法生成對應節點的element物件。

@protected

element createelement();

@override

string tostringshort()

//複寫父類的方法,設定診斷樹的一些特徵

@override

void debugfillproperties(diagnosticpropertiesbuilder properties)

@override

@nonvirtual

bool operator ==(object other) => super == other;

@override

@nonvirtual

int get hashcode => super.hashcode;

//乙個靜態方法。主要用於widget樹重新建立時復用舊的widget。只要runtimetype和key相同,就會用newwidget更新element物件的配置

static bool canupdate(widget oldwidget, widget newwidget)

static int _debugconcretesubtype(widget widget)

}

element

element 是 widget 的乙個例項化物件,它承載了檢視構建的上下文資料,是連線結構化的配置資訊到完成最終渲染的橋梁。

首先,通過 widget 樹生成對應的 element 樹;

然後,建立相應的 renderobject 並關聯到 element.renderobject 屬性上;

最後,構建成 renderobject 樹來完成布局的排列和繪製,以完成最終的渲染。

element 生命週期

呼叫 widget#createelement 建立乙個element例項,從而生成對應節點的 element 物件。這裡看下renderobjectwidget 原始碼。對於 renderobject 的建立與更新,其實是在 renderobjectelement 類中完成的。

//renderobjectwidget 是乙個抽象類。這個類中同時擁有建立 element、renderobject,以及更新 renderobject 的方法。

//實際上,renderobjectwidget 本身並不負責這些物件的建立與更新。

abstract class renderobjectwidget extends widget

@protected

void didunmountrenderobject(covariant renderobject renderobject)

}

呼叫 element#mount ,mount方法首先呼叫 element 所對應的 widget 的 createrenderobject 方法建立與 element 相關聯的 renderobject 物件,然後呼叫 element#attachrenderobject 方法將 renderobject 新增到渲染樹中插槽指定的位置。插入到渲染樹後 element 就處於 active 狀態。

abstract class element extends diagnosticabletree implements buildcontext 

_updateinheritance();

_debuglifecyclestate = _elementlifecycle.active;

}}abstract class renderobjectelement extends element

}

當父 widget 的配置資料發生變化時,同事其 state#build 返回的widget 結構與之前不同,此時就需要重新構建對應的 element 樹。當然,為使 element 能夠復用,在 element 重新構建前後會首先嘗試是否可以復用舊樹上相同位置的 element,element 節點在更新之前都會呼叫與其對應的 widget 的canupdate 方法,如果返回 true,則復用,舊的 element 會使用新的 widget 配置資料更新,反之則會建立乙個新額度 element。

當有祖先 element 決定要移除 element 時(如 widget樹結構發生了變化,導致與element 對應的 widget被移除),這時 該祖先 element 舊會呼叫 deactivatechild 方法來移除它,移除後 renderobject 也將從渲染樹種移除,然後 fragment 會 呼叫 deactivate 方法,這時狀態變為 inactive。

element 中

@protected

void deactivatechild(element child)

@mustcallsuper

void deactivate()

這時 element 舊不會再顯示到螢幕上了。為了避免再一次動畫執行過程中反覆建立、移除某個特定的element,inactive狀態的element 在當前動畫最後一幀結束前都會保留,如果在動畫執行結束後它還未能重新變成 active 狀態,那麼 flutter 將呼叫其 unmount 方法將其徹底移除,這時 element 的狀態為 defunct,將永遠不會被插入到樹中。

@mustcallsuper

void unmount()

assert(()

buildcontext

abstract class buildcontext
element 實現了這個介面,上文**已有。在element 的子類中,比如 以statelesswidget為例

abstract class statelesswidget extends widget ) : super(key: key);

@override

statelesselement createelement() => statelesselement(this);

@protected

widget build(buildcontext context);

}

statelesswidget 繼承 widget ,createelement 建立 statelesselement ,並將 this(widget) 傳入 statelesselement。statelesselement就含有 statelesswidget 的引用。

statelesselement 中,呼叫父類建構函式,將 _widget 即 外界呼叫的 widget 賦值。這裡得 widget 將其強轉。

class statelesselement extends componentelement 

}

在 statelesselement 得ubild中,將 this(element) 作為引數呼叫 widget 的 build 方法,那麼,我們常見的 build 中 buildcontext 就是 statelesselement ,實則 buildcontext 就是 與widget 對應的 element,所以我們可以通過 context 在 statelesswidget 的 build 方法中直接訪問 element 物件。

flutter 盡量讓開發者只需要關注 widget 層即可,但是,有時並不能完全遮蔽,所以 flutter framework 在 build 方引數將 element 物件傳遞出去。

Flutter中Widget的滾動布局

介紹一些常用的滾動布局,可參考flutter中文網 裡 滾動 模組 的介紹。1.listview2.gridview3.customscrollview 一 listview.官方文件中介紹listview有四種建立方式 1 listview 預設構造方法。2 builder listview.bu...

在Flutter中給widget新增動畫

在android中,可以通過通過xml建立動畫或在檢視上呼叫view.animate 對檢視進行動畫處理。在flutter中,可以通過動畫庫給widget新增動畫,將widget包裝到animation中。與android相似,在flutter中,有乙個animationcontroller控制器和...

Flutter布局總結(一) 單個widget

flutter布局機制的核心是widget 首先了解下布局結構 此ui顯示乙個行包含3列,其中每列包含乙個圖示和乙個標籤 此ui的widget樹圖如下 container是乙個widget,允許自定義其子widget。如果要新增填充 邊距 邊框或者是背景色,需要使用container來設定 在flu...