天天看點

Flutter 100: 何為 Flutter Widgets ?

小菜學習 **Flutter** 有一段時間了,其中 **Flutter** 的核心思想是 **Everything is Widget**;但是什麼是 **Widget** 它與我們常說的 **Element** 和 **RenderObject** 有什麼關系呢,小菜就個人了解簡單整理一下;           

Widget

源碼分析

abstract class Widget extends DiagnosticableTree {
  const Widget({ this.key });

  final Key key;

  @protected
  Element createElement();

  @override
  String toStringShort() {
    return key == null ? '$runtimeType' : '$runtimeType-$key';
  }

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
  }

  static bool canUpdate(Widget oldWidget, Widget newWidget) {
    return oldWidget.runtimeType == newWidget.runtimeType
        && oldWidget.key == newWidget.key;
  }
}           
簡單分析源碼和注釋可得,**Widget** 繼承自 **DiagnosticableTree** 是該樹上的一個對象;           
  1. Widget 描述了 Element 的配置,隻是用來儲存屬性的容器;
  2. createElement() 用來生成一個 Element 對象并添加到 Widget 樹中;
  3. toStringShort() 是對該 Widget 的簡短說明,包括 Widget 類型和對應的 Key 等;
  4. canUpdate() 用來判斷目前 Widget 是否重建,當兩個新舊 runtimeType 和 key 相同時則更新 Widget 否則會建立一個 Widget 替代老舊的 Widget;

子類 Widget

**Widget** 主要有三類子類 **Widget**;分别是組合類 **Widget**(**StatelessWidget/StatefulWidget**)、代理類 **Widget**(**ProxyWidget**)、渲染類 **Widget**(**RenderObjectWidget**);           
Flutter 100: 何為 Flutter Widgets ?
1. StatelessWidget / StatefulWidget
**StatelessWidget** 是狀态不可變的 **Widget**,主要通過 **build()** 方法,把一個或多個 **Widget** 整合成一個新的 **Widget**;這也完全符合 **Flutter** 【組合大于繼承】的思想;**StatelessWidget** 的核心方法就是 **build()** 方法,把多個 **Widget** 組合包裝成一個新的 **Widget**;           
abstract class StatelessWidget extends Widget {
  const StatelessWidget({ Key key }) : super(key: key);

  @override
  StatelessElement createElement() => StatelessElement(this);
  
  @protected
  Widget build(BuildContext context);
}           
**StatefulWidget** 是狀态可變的 **Widget**,而其核心是 **State** 狀态管理;常用的 **setState(){}** 便是用來更新重構 **Widget**;           
abstract class StatefulWidget extends Widget {
  const StatefulWidget({ Key key }) : super(key: key);

  @override
  StatefulElement createElement() => StatefulElement(this);

  @protected
  State createState();
}           
**State** 用于處理 **StatefulWidget** 業務邏輯和狀态管理,有 **_StateLifecycle** 生命周期進行維護;           
  1. created 對象建立,在 initState() 生命周期時執行;
  2. initialized 對象初始化,在 didChangeDependencies() 過程中執行;initState() 隻是建立了 State 對象但是未初始化完成;
  3. ready 對象準備好且 dispose() 方法未執行;
  4. defunct 對象銷毀,在 dispose() 執行時進行銷毀;
2. ProxyWidget
**ProxyWidget** 作為一個抽象的代理 **Widget** 并沒有實質性的作用,隻是在父類和子類需要傳遞資訊時使用;主要有 **InheritedWidget** 和 **ParentDataWidget** 兩類;           
abstract class ProxyWidget extends Widget {
  const ProxyWidget({ Key key, @required this.child }) : super(key: key);

  final Widget child;
}           
使用過 **Bloc** 或 **Provider** 等狀态管理的朋友都了解過 **InheritedWidget**,主要都是對 **InheritedWidget** 的優化和封裝;可以在樹結構中傳遞資訊,當使用 **InheritedWidget** 時,子類狀态變更時可以通知父類進行對應的變更;小菜簡單了解為資料上移;

  而 **ParentDataWidget** 與 **InheritedWidget** 作用方向相反,用于為具有多個子類的 **RenderObjectWidget** 提供對于的配置等,例如 **Stack** 使用已定位好的父類 **Widget** 來定位每個子 **Widget**;小菜簡單了解為資料下移;

  **InheritedWidget** 和 **ParentDataWidget** 涉及内容較多,小菜暫不做深入研究;
           
3. RenderObjectWidget
**RenderObjectWidget** 是真正用于繪制渲染 **Widget**,一切在螢幕上展示的 **Widget** 根本上都離不開 **RenderObjectWidget**;它提供了 **RenderObjectElement** 的建立配置和 **RenderObject** 渲染對象的規定,提供了應用程式的實際渲染;           
abstract class RenderObjectWidget extends Widget {
  const RenderObjectWidget({ Key key }) : super(key: key);

  @override
  RenderObjectElement createElement();

  @protected
  RenderObject createRenderObject(BuildContext context);

  @protected
  void updateRenderObject(BuildContext context, covariant RenderObject renderObject) { }
  
  @protected
  void didUnmountRenderObject(covariant RenderObject renderObject) { }
}           
**updateRenderObject** 是在 **Widget** 更新後,修改對應的 **RenderObject** 對象,在每次更新時都會調用;**didUnmountRenderObject** 是在 **RenderObject** 在 **Render Tree** 中删除時調用;           

Key / GlobalKey

**Key** 可以用來控制在 **Widget** 重建時是否與其他 **Widget** 比對,隻有 **Key** 和 **runtimeType** 同時一緻才會認為是同一個 **Widget**;**Key** 在建構相同類型 **Widget** 的多個執行個體時很有用,例如 **List** 清單中多個相同類型的 **item**,可以提高清單效率;

  **GlobalKey** 可以作為應用全局唯一辨別,在整個 **Widget** 層級中都是唯一的,可以使用 **GlobalKey** 來檢索與 **Widget** 關聯的狀态;           
**Widget** 與 **Element** 和 **RenderObject** 都是密不可分的,之後進一步學習 **Element** 和 **RenderObject**;小菜對底層的研究還不夠深入;如有錯誤,請多多指導!
           
來源: 阿策小和尚

繼續閱讀