1. Introduction
In the previous three articles of this series, three core elements of Flutter were introduced: Widget, Element, and RenderObject. The relationship between them is also introduced. In this article, we will analyze the well-known concepts of Flutter, including “Widget, Element and RenderObject tree”, based on the previous article, in order to deepen readers’ understanding of the Flutter Framework.
2. Concepts and functions of Widget, Element and RenderObject trees
Learning about Flutter often comes across one concept: Widget, Element, RenderObject tree. So what are Widget, Element, RenderObject trees? The Widget, Element, and RenderObject trees in Flutter refer to the Widget Tree, Element Tree, and RenderObject Tree. As you can see from the previous articles, their functions are as follows:
- Widget Tree
The Widget Tree is the configuration of the entire UI that the Flutter developer uses to tell the Framework what the UI should look like. The Widget Tree is the main object that we deal with.
- Element Tree
The Element Tree is generated by Widget Tree. Its main function is to maintain the Tree structure of UI elements and associate widgets and RenderObjects to the Tree.
- RenderObject Tree
The RenderObject Tree is also generated by the Widget Tree. It is responsible for the rendering and layout of the interface and is the underlying system. Flutter developers generally do not need to operate the Tree directly. To further understand the Widget, Element, and RenderObject trees, we will use an example below.
3. Widget, Element, RenderObject tree examples
Example code is as follows:
class TreeTest extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text("tree test", textDirection: TextDirection.ltr) ); }}Copy the code
The example is simple, displaying a Text in the middle of the page with the Text as Tree Test. The running results are as follows:
The corresponding Widget Tree, Element Tree and RenderObject Tree are shown as follows:
Combine the previous three articles in this series: Flutter framework analysis (ii) –Widget, Flutter framework analysis (III) –Element, Flutter framework analysis (IV) — RenderObject. As can be seen from the figure above:
- Widget TreeIn aWidget, corresponding toElement TreeIn aElement.
- Element TreeIn theElementThere may not be a correspondingRenderObject, e.g.StatelessElementSubordinate to theComponentElementThere is no correspondingRenderObjectIt is more basic for compositionElement.
- Widget TreeIs the root node ofRenderObjectToWidgetAdapterAnd its correspondingElementisRenderObjectToWidgetElement, this isElement TreeThe root node ofRenderObjectisRenderView, this isRenderObject TreeThe root node of.
One notable feature in the figure above is Text, which you can see has a sub-widget: RichText, but we only defined a Text component in the example. What’s going on here? We can trace the source code.
Text is defined as follows:
class Text extends StatelessWidget
Copy the code
So it’s just a Widget for composing other, more basic widgets. What really controls the text attributes is the RichText defined in the build function, which has the following source code:
@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 nullsoftWrap: 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;
}
Copy the code
So you can see in Widget Tree that the child of Text is RichText.
4. Mapping between Widgets and Elements
As mentioned above, the Widget in the Widget Tree corresponds to the Element in the Element Tree one-to-one. However, we mentioned that one Widget object can correspond to multiple Element objects in the Flutter framework. Doesn’t that contradict each other? No, a Widget object is not the same as a Widget object in the Widget Tree, because there are also Slot properties in the Widget Tree. A Widget object plus its position in the Widget Tree is relative to a Widget object in a Widget Tree.
Here is an example of a Widget object that corresponds to multiple Element objects:
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");
returnColumn( children: <Widget>[ testText, testText, ], ); }}Copy the code
The corresponding Widget Tree and Element Tree are as follows:
In the example above, the Widget Tree is on the left and the Element Tree is on the right. In Widget Tree, Column has two child nodes, but the two children use the same Text object, so the Text object appears in two different slots. In this case, two different StatelessElement objects are generated in the Element Tree. That is, a Text object corresponds to two StatelessElement objects.
Notice that the Widget Tree and Element Tree do not contain the root node.
5. Summary
This article introduces the common concepts of Flutter: Widget Tree, Element Tree, RenderObject Tree. And through an example, explained the relationship between the three trees. The main points of this paper are as follows:
- Widget TreeIn aWidget, corresponding toElement TreeIn aElementBut aWidgetThere may be more than oneElementBecause of oneWidgetAnd it’s on theWidget TreeThe positions in theWidget TreeOne of theWidget.
- Element TreeIn theElementThere may not be a correspondingRenderObject, e.g.StatelessElementSubordinate to theComponentElementThere is no correspondingRenderObjectIt is more basic for compositionElement.
- Widget TreeIs the root node ofRenderObjectToWidgetAdapterAnd its correspondingElementisRenderObjectToWidgetElement, this isElement TreeThe root node ofRenderObjectisRenderView, this isRenderObject TreeThe root node of.
6. Reference documents
Flutter architectural overview
7. Related articles
Flutter framework Analysis (1) — Overview of the Flutter framework Analysis (2) — Widget Flutter framework analysis (3) — Element Flutter framework Analysis (4) — RenderObject -Constraint Flutter framework Analysis (7) -relayoutBoundary Flutter framework analysis (8) -Platform Channel Flutter framework analysis – Parent Data Flutter framework Analysis -InheritedWidget