在本系列文章的前面三篇文章中,已經分別介紹Flutter的三種核心元素:Widget,Element,和RenderObject。並介紹了它們之間的關係。在這篇文章中,將在前面文章的基礎上,對Flutter中很是出名的概念「Widget,Element,RenderObject樹」進行剖析,以此加深讀者對Flutter Framework的理解。markdown
學習Flutter的時候常常會遇到一個概念:Widget,Element,RenderObject樹。那什麼是Widget,Element,RenderObject樹呢?Flutter中的Widget,Element,RenderObject樹指的是:Widget Tree, Element Tree, RenderObject Tree。從前面幾篇文章能夠知道,它們的做用分別以下:架構
Widget Tree是整個UI界面的配置,Flutter開發者經過Widget Tree告訴Framework想要繪製的UI界面是什麼樣的,這棵樹是咱們主要打交道的對象。app
Element Tree是經過Widget Tree生成的,其主要做用是維護UI元素的樹形結構,並將Widget和RenderObject關聯到樹上。框架
RenderObject Tree也是經過Widget Tree生成的,其主要做用是負責界面的繪製和佈局,是屬於底層系統,Flutter開發者通常不須要直接操做該樹。 爲了加深對這Widget,Element,RenderObject樹的理解,下面將使用一個例子進行講解。less
示例代碼以下:ide
class TreeTest extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text("tree test", textDirection: TextDirection.ltr)
);
}
}
複製代碼
該示例很簡單,在頁面中間顯示一個Text,文案爲tree test。其運行結果以下:函數
其代碼對應的Widget Tree,Element Tree,RenderObject Tree的示意圖以下:oop
結合本系列文章的前面三篇:Flutter框架分析(二)--Widget,Flutter框架分析(三)--Element,Flutter框架分析(四)-RenderObject。由上圖能夠看出:佈局
在上圖中一個值得注意的地方是Text,從圖中能夠看到它有個子Widget:RichText,可是咱們在示例中只定義了一個Text組件,這是怎麼回事呢?咱們能夠追蹤下源碼。post
Text的定義以下:
class Text extends StatelessWidget 複製代碼
所以它只是一個用於組合其餘更基礎的Widget,真正控制文案屬性的是在build函數中定義的RichText,其源碼以下:
@override
Widget build(BuildContext context) {
final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context);
TextStyle effectiveTextStyle = style;
if (style == null || style.inherit)
effectiveTextStyle = defaultTextStyle.style.merge(style);
if (MediaQuery.boldTextOverride(context))
effectiveTextStyle = effectiveTextStyle.merge(const TextStyle(fontWeight: FontWeight.bold));
Widget result = RichText(
textAlign: textAlign ?? defaultTextStyle.textAlign ?? TextAlign.start,
textDirection: textDirection, // RichText uses Directionality.of to obtain a default if this is null.
locale: locale, // RichText uses Localizations.localeOf to obtain a default if this is null
softWrap: softWrap ?? defaultTextStyle.softWrap,
overflow: overflow ?? defaultTextStyle.overflow,
textScaleFactor: textScaleFactor ?? MediaQuery.textScaleFactorOf(context),
maxLines: maxLines ?? defaultTextStyle.maxLines,
strutStyle: strutStyle,
textWidthBasis: textWidthBasis ?? defaultTextStyle.textWidthBasis,
textHeightBehavior: textHeightBehavior ?? defaultTextStyle.textHeightBehavior ?? DefaultTextHeightBehavior.of(context),
applyTextScaleFactorToWidgetSpan: _applyTextScaleFactorToWidgetSpan,
text: TextSpan(
style: effectiveTextStyle,
text: data,
children: textSpan != null ? <InlineSpan>[textSpan] : null,
),
);
if (semanticsLabel != null) {
result = Semantics(
textDirection: textDirection,
label: semanticsLabel,
child: ExcludeSemantics(
child: result,
),
);
}
return result;
}
複製代碼
因此在Widget Tree中能夠看到Text的child是RichText。
上文已經說過,Widget Tree中的Widget和Element Tree中的Element關係是一一對應的,可是咱們在Flutter框架分析(二)--Widget一文中曾經說過,一個Widget對象能夠對應多個Element對象。那這不是互相矛盾了嗎?其實不是的,一個Widget對象並不等同於一個Widget Tree中的Widget對象,由於在Widget Tree中還有個位置屬性(Slot)。一個Widget對象加上其在Widget Tree中的位置,才相對於一個Widget Tree中的Widget對象。
如下是一個Widget對象對應多個Element對象的一個示例:
class SameWidgetMultiElementWidget1 extends StatefulWidget {
@override
_SameWidgetMultiElementWidgetState createState() => new _SameWidgetMultiElementWidgetState();
}
class _SameWidgetMultiElementWidgetState extends State<SameWidgetMultiElementWidget1> {
int count = 0;
@override
Widget build(BuildContext context) {
Text testText = Text("multi element");
return Column(
children: <Widget>[
testText,
testText,
],
);
}
}
複製代碼
其對應的Widget Tree和Element Tree以下:
在上面示例中,左邊是Widget Tree,右邊是Element Tree。在Widget Tree中,Column有兩個子節點,可是這兩個子節點使用的是同一個Text對象,所以這個Text對象出如今兩個不一樣的位置(Slot),此時在Element Tree會生成兩個不一樣的StatelessElement對象,即一個Text對象對應兩個StatelessElement對象。
注意該Widget Tree和Element Tree未包含根節點。
本文主要介紹了Flutter中的常見概念:Widget Tree, Element Tree, RenderObject Tree。並經過一個例子,講解了這三棵樹之間的關係。本文的重點以下:
Flutter architectural overview
Flutter框架分析(一)--架構總覽
Flutter框架分析(二)-- Widget
Flutter框架分析(三)-- Element
Flutter框架分析(四)-RenderObject
Flutter框架分析(六)-Constraint
Flutter框架分析(七)-relayoutBoundary
Flutter框架分析(八)-Platform Channel
Flutter框架分析- Parent Data
Flutter框架分析 -InheritedWidget