Flutter學(xué)習(xí)筆記(2)

繼上一篇 Flutter學(xué)習(xí)筆記(1)介紹了一下Flutter框架構(gòu)造,本篇主講Flutter的視圖體系,下一篇開始布局

引言

  • Flutter官方文檔里的一句話:you build your UI out of widgets(萬物皆控件)
  • 首先,F(xiàn)lutter沒有css,沒有xml,Dart語言是面向?qū)ο蟮?/li>
  • 其次Widget并不是我們真正看到的視圖,背后究竟是什么?
  • Flutter界面開發(fā)是一種響應(yīng)式編程,而Widget又是一層不變的,那真正的渲染、布局、刷新是誰來處理?

Flutter的視圖體系

Flutter Framework提供了三種視圖樹,即:Widget Element RenderObject

視圖樹.png

  • Widget

官方文檔:
Describes the configuration for an Element.
Widgets are the central class hierarchy in the Flutter framework. A widget is an immutable description of part of a user interface. Widgets can be inflated into elements, which manage the underlying render tree.

解釋一下:Widget 是用來描述如何創(chuàng)建Element 的,Widget是一個不可變對象,它可以被復(fù)用,請注意,這里的復(fù)用不是指在兩次渲染的時候?qū)ο髲呐f樹中拿過來放到新樹,而是在同一個 Widget Tree 中,某個子 Widget 可以出現(xiàn)多次,因為它只是一個 description。
在一次渲染中,F(xiàn)lutter Framework 會調(diào)用 Widget 的 方法,這個方法會創(chuàng)建一個新的對應(yīng)的 對象并返回。所以即使 Widget 被重復(fù)使用,框架還是會創(chuàng)建多個不同的 Element 對象。
到這里,Widget 的工作就暫告一段落了。

Widget這個類中都包含哪些屬性:

  1. KEY key
  2. int hasCode
  3. TYPE runtimeType

Widget是用戶界面的一部分,并且是不可變的(immutable)。Widget會被inflate到Element,并由Element管理底層渲染樹。Widget本身沒有可變狀態(tài)(所有的字段必須是final)。如果想要把可變狀態(tài)與Widget關(guān)聯(lián)起來,可以使用StatefulWidget,StatefulWidget通過使用StatefulWidget.createState方法創(chuàng)建State對象,并將之?dāng)U充到Element以及合并到樹中;

  • Element
  1. 負(fù)責(zé)狀態(tài)和生命周期管理的對象,實際上很少需要去自己實現(xiàn) Element

  2. Element 是 Widget 的實例體現(xiàn),上面說過 Widget 可以重復(fù)使用,但是 Flutter Framework 仍然會對這幾個相同的 Widget 依次創(chuàng)建幾個全新的 Element。 一次渲染會生成一個 Element Tree 并放在內(nèi)存中,在下次渲染時 Flutter Framework 會用嘗試用新的 Widget 去更新舊的 Element,此時 Element 被復(fù)用,這里的復(fù)用是指不再創(chuàng)建新的 Element 的對象了,但每個相同的 Widget 還是各自對應(yīng)了一個不同的 Element

  3. 那么 Element 到底是做什么的呢,概括地說就是保存了一個樹形結(jié)構(gòu)以便更新時做 diff、patch 和管理組件生命周期用的,由于 Widget 都是沒有狀態(tài)的,如果你想修改 Widget 的某一屬性就必須要重新創(chuàng)建一遍 Widget,而 StatefulWidget 內(nèi)部包含 State,如果重新創(chuàng)建了狀態(tài)就會丟失,所以必須有一個地方來存儲這些暫時的狀態(tài)。
    用 StatefulWidget 來舉例說明吧。 第一次渲染時,StatefulWidget 通過 createElement 創(chuàng)建出一個 StatefulElement,然后我們來看 StatefulElement 的構(gòu)造方法

StatefulElement(StatefulWidget widget)
    : _state = widget.createState(), super(widget) {
    assert(() {
      if (!_state._debugTypesAreRight(widget)) {
        throw new FlutterError(
          'StatefulWidget.createState must return a subtype of State<${widget.runtimeType}>\n'
          'The createState function for ${widget.runtimeType} returned a state '
          'of type ${_state.runtimeType}, which is not a subtype of '
          'State<${widget.runtimeType}>, violating the contract for createState.'
        );
      }
      return true;
    }());
    assert(_state._element == null);
    _state._element = this;
    assert(_state._widget == null);
    _state._widget = widget;
    assert(_state._debugLifecycleState == _StateLifecycle.created);
}

可以看到,StatefulElement 內(nèi)部會負(fù)責(zé)創(chuàng)建和保存 State,這樣就是為什么 StatefulWidget 被重新創(chuàng)建了而內(nèi)部的狀態(tài)不會丟失的原因。
然后在 Widget Tree 發(fā)生變化的時候,F(xiàn)lutter Framework 通過 Element 的 update 來根據(jù)新 Widget 更新舊 Element:

@override
void update(StatefulWidget newWidget) {
    super.update(newWidget);
    assert(widget == newWidget);
    final StatefulWidget oldWidget = _state._widget;
    // Notice that we mark ourselves as dirty before calling didUpdateWidget to
    // let authors call setState from within didUpdateWidget without triggering
    // asserts.
    _dirty = true;
    _state._widget = widget;
    try {
      _debugSetAllowIgnoredCallsToMarkNeedsBuild(true);
      _state.didUpdateWidget(oldWidget);
    } finally {
      _debugSetAllowIgnoredCallsToMarkNeedsBuild(false);
    }
    rebuild();
}
  • RenderObject
    官網(wǎng)定義:An object in the render tree.渲染樹中的一個對象。從其名字,我們可以很直觀地知道,它就是負(fù)責(zé)渲染的工作;
    RenderObject的屬性太多,且該類的細(xì)節(jié)涉及很多渲染知識,我們會在后面的系列中再詳細(xì)說明其工作原理。

總結(jié)

  • Widget:存放渲染內(nèi)容、視圖布局信息,widget的屬性最好都是immutable

  • Element:存放上下文,通過Element遍歷視圖樹,Element同時持有Widget和RenderObject

  • RenderObject:根據(jù)Widget的布局屬性進(jìn)行l(wèi)ayout,paint Widget傳人的內(nèi)容

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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