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

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

引言

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

Flutter的視圖體系

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

視圖樹(shù).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 是用來(lái)描述如何創(chuàng)建Element 的,Widget是一個(gè)不可變對(duì)象,它可以被復(fù)用,請(qǐng)注意,這里的復(fù)用不是指在兩次渲染的時(shí)候?qū)?duì)象從舊樹(shù)中拿過(guò)來(lái)放到新樹(shù),而是在同一個(gè) Widget Tree 中,某個(gè)子 Widget 可以出現(xiàn)多次,因?yàn)樗皇且粋€(gè) description。
在一次渲染中,F(xiàn)lutter Framework 會(huì)調(diào)用 Widget 的 方法,這個(gè)方法會(huì)創(chuàng)建一個(gè)新的對(duì)應(yīng)的 對(duì)象并返回。所以即使 Widget 被重復(fù)使用,框架還是會(huì)創(chuàng)建多個(gè)不同的 Element 對(duì)象。
到這里,Widget 的工作就暫告一段落了。

Widget這個(gè)類(lèi)中都包含哪些屬性:

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

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

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

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

  3. 那么 Element 到底是做什么的呢,概括地說(shuō)就是保存了一個(gè)樹(shù)形結(jié)構(gòu)以便更新時(shí)做 diff、patch 和管理組件生命周期用的,由于 Widget 都是沒(méi)有狀態(tài)的,如果你想修改 Widget 的某一屬性就必須要重新創(chuàng)建一遍 Widget,而 StatefulWidget 內(nèi)部包含 State,如果重新創(chuàng)建了狀態(tài)就會(huì)丟失,所以必須有一個(gè)地方來(lái)存儲(chǔ)這些暫時(shí)的狀態(tài)。
    用 StatefulWidget 來(lái)舉例說(shuō)明吧。 第一次渲染時(shí),StatefulWidget 通過(guò) createElement 創(chuàng)建出一個(gè) StatefulElement,然后我們來(lái)看 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)部會(huì)負(fù)責(zé)創(chuàng)建和保存 State,這樣就是為什么 StatefulWidget 被重新創(chuàng)建了而內(nèi)部的狀態(tài)不會(huì)丟失的原因。
然后在 Widget Tree 發(fā)生變化的時(shí)候,F(xiàn)lutter Framework 通過(guò) Element 的 update 來(lái)根據(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.渲染樹(shù)中的一個(gè)對(duì)象。從其名字,我們可以很直觀地知道,它就是負(fù)責(zé)渲染的工作;
    RenderObject的屬性太多,且該類(lèi)的細(xì)節(jié)涉及很多渲染知識(shí),我們會(huì)在后面的系列中再詳細(xì)說(shuō)明其工作原理。

總結(jié)

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

  • Element:存放上下文,通過(guò)Element遍歷視圖樹(shù),Element同時(shí)持有Widget和RenderObject

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容