As the 21st article in this series, this article will introduce the overall rendering principle of Flutter Framework from a different perspective, and deeply analyze the drawing process of Flutter after the formation of Layer, so that developers can have a clearer understanding of the rendering principle and implementation logic of Flutter.
Article summary address:
A complete series of articles on Flutter
A series of articles on the world outside Flutter
1. Layer related review
To review, we know that the controls in Flutter go through widgets -> Element -> RenderObject -> Layer. The composition of Layer is determined by the isRepaintBoundary flag bit in the RenderObject.
When setState is called, the RenderObject looks up to the parent node and depending on whether isRepaintBoundary is true, determines whether or not to trigger a redraw from there, in other words, which areas to update.
For example, when Navigator jumps to different routing pages, there is a RepaintBoundary control inside each page. The isRepaintBoundary marker bit in the corresponding RenderRepaintBoundary is true. Thus, an independent Layer is formed between routing pages.
Therefore, the related RenderObjects together form the Layer, and the Layer Tree made up of the layers is submitted to the Flutter Engine to draw the image.
So how does Layer work? What is its nature? How does the Layer of the Flutter Framework be submitted to Engine?
Draw in the Flutter Framework
With the previous Layer question in mind, let’s start with an assumption: how can we render a scene without the controls encapsulated in the Flutter Framework? Or how do you create a Layer?
For example, as shown in the following code, you see a 100 x 100 blue square in the center, and there are no widgets, RenderObjects, or even layers in the code. Instead, the relatively unfamiliar objects such as PictureRecorder, Canvas and SceneBuilder were used to complete the painting, and window.render was executed at the end.
import 'dart:ui' as ui;
void main() { ui.window.onBeginFrame = beginFrame; ui.window.scheduleFrame(); } void beginFrame(Duration timeStamp) { final double devicePixelRatio = ui.window.devicePixelRatio; Final UI.picturerecOrder Recorder = UI.picturerecOrder (); Canvas Canvas = uI.canvas (Recorder); // Create a Canvas final UI based on the artboard. canvas.scale(devicePixelRatio, devicePixelRatio); Var centerX = UI. Window. PhysicalSize. Width / 2.0; Var centerY. = UI window. PhysicalSize. Height / 2.0; DrawRect (rect.fromCenter (center: offset.zero, width: 100, height: 100), new Paint().. color = Colors.blue); Picture Picture = recorder. EndRecording (); final ui.SceneBuilder sceneBuilder = ui.SceneBuilder() .. pushOffset(centerX, centerY) .. addPicture(ui.Offset.zero, picture) .. pop(); ui.window.render(sceneBuilder.build()); }Copy the code
Because Canvas creation in Flutter must have a PictureRecorder, which creates a picture to record drawing, in the above code:
- I’m gonna create
PictureRecorder
; - Then use the
PictureRecorder
To create theCanvas
; - After using
Canvas
Draw a small blue square; - Pass after drawing
SceneBuilder
的pushOffset
和addPicture
Loaded the drawn content; - through
window.render
Draw the picture.
Note that ⚠️ : the render method is limited to onBeginFrame or onDrawFrame, so the upper code will have window. OnBeginFrame = beginFrame; . There are many similar examples in the official examples/layers/raw/.
You can see that the last step of the underlying draw of the Flutter Framework is window.render, as shown in the following code: The render method requires a Scene object, and the render method is a native method, which means that the Flutter Framework ultimately submits to the Engine a Scene.
void render(Scene scene) native 'Window_render';
Copy the code
theScene
What is it? As mentioned earlierLayer
Where is it? What is the relationship between them?
3. The difference between Scene and Layer
In a Flutter, Scene is a Native object that corresponds to the scene.cc structure of Engine, which contains a layer_tree_for drawing. The Scene in Engine is related to layer_tree_.
Then, in the Flutter Framework, scenes can only be built by SceneBuilder. SceneBuilder has many methods, such as: Engine creates a corresponding EngineLayer after executing the pushOffset, pushClipRect, and pushOpacity methods.
OffsetEngineLayer pushOffset(double dx, double dy, { OffsetEngineLayer oldLayer }) {
assert(_debugCheckCanBeUsedAsOldLayer(oldLayer, 'pushOffset'));
final OffsetEngineLayer layer = OffsetEngineLayer._(_pushOffset(dx, dy));
assert(_debugPushLayer(layer));
return layer;
}
EngineLayer _pushOffset(double dx, double dy) native 'SceneBuilder_pushOffset';
Copy the code
So SceneBuilder can create an “EngineLayer” through push and other related methods before building the Scene. For example, SceneBuilder creates the corresponding layer offset through pushOffset.
Then look at the Layer of the Flutter Framework. As shown in the following code, the EngineLayer parameter exists on the Layer by default, so the Layer must be related to SceneBuilder.
@protected
ui.EngineLayer get engineLayer => _engineLayer;
@protected
set engineLayer(ui.EngineLayer value) {
_engineLayer = value;
if(! alwaysNeedsAddToScene) {if(parent ! = null && ! parent.alwaysNeedsAddToScene) { parent.markNeedsAddToScene(); } } } ui.EngineLayer _engineLayer; /// Override this method to upload this layer to the engine. /// /// Return the engine layerfor retained rendering. When there no
/// corresponding engine layer, null is returned.
@protected
void addToScene(ui.SceneBuilder builder, [ Offset layerOffset = Offset.zero ]);
Copy the code
Second, there is a key method in Layer: AddToScene, you can see from the comments that this method is implemented by a subclass, and you can get an EngineLayer, and this method needs a SceneBuilder, The implementation of the query method happens to be OffsetLayer and PictureLayer.
So the following code can be seen in the addToScene method implementation of OffsetLayer and PictureLayer:
PictureLayer
Call theSceneBuilder
的addPicture
;OffsetLayer
Call theSceneBuilder
的pushOffset
;
Class PictureLayer extends Layer {··· @Override void addToScene(uI.sceneBuilder Builder, [ Offset layerOffset = Offset.zero ]) { builder.addPicture(layerOffset, picture, isComplexHint: isComplexHint, willChangeHint: willChangeHint); } ··· ·} class extends ContainerLayer {··· ···} Class extends ContainerLayer ({Offset Offset = offset.zero}) : _offset = Offset; @override void addToScene(ui.SceneBuilder builder, [ Offset layerOffset = Offset.zero ]) { engineLayer = builder.pushOffset( layerOffset.dx + offset.dx, layerOffset.dy + offset.dy, oldLayer: _engineLayer as ui.OffsetEngineLayer, ); addChildrenToScene(builder); builder.pop(); }...}Copy the code
So here SceneBuilder and Layer are successfully connected by EngineLayer and addToScene methods, and the Scene submitted by window.render is constructed by SceneBuilder, Therefore, as shown in the figure below, Layer and Scene are together in this way.
The code in the front of the little blue box is shown in the following code, which is modified to use Layer. You can see that this implementation is closer to the implementation of the Flutter Framework: The Layer tree is built from rootLayer level by appEnd, and when rootLayer calls addToScene, because the addChildrenToScene method is executed, So we go down to addToScene of the Child Layer.
import 'dart:ui' as ui;
void main() {
ui.window.onBeginFrame = beginFrame;
ui.window.scheduleFrame();
}
void beginFrame(Duration timeStamp) {
final double devicePixelRatio = ui.window.devicePixelRatio;
///创建一个画板
final ui.PictureRecorder recorder = ui.PictureRecorder();
///基于画板创建一个 Canvas
final ui.Canvas canvas = ui.Canvas(recorder);
canvas.scale(devicePixelRatio, devicePixelRatio);
var centerX = ui.window.physicalSize.width / 2.0;
var centerY = ui.window.physicalSize.height / 2.0;
///画一个 100 的剧中蓝色
canvas.drawRect(Rect.fromCenter(center: Offset.zero, width: 100, height: 100),
new Paint()..color = Colors.blue);
final ui.SceneBuilder sceneBuilder = ui.SceneBuilder();
OffsetLayer rootLayer = new OffsetLayer();
OffsetLayer offsetLayer = new OffsetLayer(offset: Offset(centerX, centerY));
rootLayer.append(offsetLayer);
PictureLayer pictureLayer = new PictureLayer(Rect.zero);
pictureLayer.picture = recorder.endRecording();
offsetLayer.append(pictureLayer);
rootLayer.addToScene(sceneBuilder);
ui.window.render(sceneBuilder.build());
}
Copy the code
4. Varieties of Layer
Here is an additional description of the common layers of A Flutter, as shown in the following figure. There are ContainerLayer and non-containerlayer in a Flutter.
ContainerLayer can have child nodes with the append method, which can be divided into:
- Displacement of the class (
OffsetLayer
/TransformLayer
); - Transparent class (
OpacityLayer
) - Cut class (
ClipRectLayer
/ClipRRectLayer
/ClipPathLayer
); - Shadow class (
PhysicalModelLayer
)
Why do these layers need to be ContainerLayer? Because these layers are pixel composition operations, they do not have the ability to “depict” the controls themselves, just like the previous example of the blue square, if you want to display the picture, you generally need to combine with PictureLayer.
For example, inside the RenderClipRRect of the ClipRRect control, the ClipRRectLayer can be created when pushClipRRect, The newly created ClipRRectLayer adds children to the parent Layer using the appendLayer method that triggers the Append operation.
Non-containerlayer typically does not have child nodes, such as:
PictureLayer
It is used to draw images on which the controls on Flutter are basically drawn;TextureLayer
Is for external textures, such as video playback or camera data;PlatformViewLayer
It’s for iOSPlatformView
Use of related embedded textures;
For example, the Canvas for control drawing comes from PaintingContext, The PaintingContext is rendered with _repaintCompositedChild and the Picture is submitted to the picturelayer.picture as shown below.
void stopRecordingIfNeeded() {
if(! _isRecording)return;
_currentLayer.picture = _recorder.endRecording();
_currentLayer = null;
_recorder = null;
_canvas = null;
}
Copy the code
Five, Layer inside and outside repair
Now that you know how the Layer is rendered, it’s time to refresh and reuse the Layer.
We know that when the isRepaintBoundary of the RenderObject is ture, the Flutter Framework automatically creates an OffsetLayer to “load” the region. Screen updates inside the Layer generally do not affect other layers.
theLayer
How is it updated? That’s where it comes inLayer
The inside of themarkNeedsAddToScene
和 updateSubtreeNeedsAddToScene
These two methods.
As shown in the following code, the markNeedsAddToScene method simply marks the _needsAddToScene in the Layer as true; And updateSubtreeNeedsAddToScene method is to iterate through all the child Layer, By recursive call updateSubtreeNeedsAddToScene () to determine whether there is a child need _needsAddToScene, if is then set himself on tag to true.
@protected
@visibleForTesting
void markNeedsAddToScene() {
// Already marked. Short-circuit.
if (_needsAddToScene) {
return;
}
_needsAddToScene = true;
}
@override
void updateSubtreeNeedsAddToScene() {
super.updateSubtreeNeedsAddToScene();
Layer child = firstChild;
while (child != null) {
child.updateSubtreeNeedsAddToScene();
_needsAddToScene = _needsAddToScene || child._needsAddToScene;
child = child.nextSibling;
}
}
Copy the code
Isn’t it similar to setState calling markNeedsBuild and marking itself _dirty? When _needsAddToScene is true, addToScene at the corresponding Layer will be called. Layer reuse is triggered when _needsAddToScene of the Layer is false and _engineLayer is not empty.
void _addToSceneWithRetainedRendering(ui.SceneBuilder builder) {
if(! _needsAddToScene && _engineLayer ! = null) { builder.addRetained(_engineLayer);return;
}
addToScene(builder);
_needsAddToScene = false;
}
Copy the code
Yes, a Layer whose _needsAddToScene is false indicates that it does not need to update, and the Layer’s EngineLayer exists, so it can be reused. For example: when a new page is opened, the bottom page does not change, it only participates in the composition of the picture, so for the bottom page, its “Layer” can be directly reused to participate in the drawing.
themarkNeedsAddToScene
When will it be called?
As shown in the figure below, when the parameters of the Layer child, such as PictureLayer’s picture and OffsetLayer’s offset change, the Layer will actively call markNeedsAddToScene to mark itself as “dirty”. In addition, when the Layer’s engineLayer changes, it will try to trigger the parent node’s Layer to call markNeedsAddToScene, so that the parent node will also change accordingly.
@protected
set engineLayer(ui.EngineLayer value) {
_engineLayer = value;
if(! alwaysNeedsAddToScene) {if (parent != null && !parent.alwaysNeedsAddToScene) {
parent.markNeedsAddToScene();
}
}
}
Copy the code
And updateSubtreeNeedsAddToScene is triggered when buildScene, call before addToScene updateSubtreeNeedsAddToScene again to judge the child nodes, To determine if a change is needed.
ui.Scene buildScene(ui.SceneBuilder builder) {
List<PictureLayer> temporaryLayers;
assert(() {
if (debugCheckElevationsEnabled) {
temporaryLayers = _debugCheckElevations();
}
return true; } ()); updateSubtreeNeedsAddToScene(); addToScene(builder); _needsAddToScene =false;
final ui.Scene scene = builder.build();
return scene;
}
Copy the code
The Layer structure of the Flutter Framework
Render _window. Render is called in the compositeFrame method of the RenderView. The RenderView is initialized in the initRendererBinding; InitRenderView is called in initInstances, which is runApp.
RenderView is created at runApp, and the compositeFrame inside the RenderView is used to render the Layer rendering via _window. Render.
void compositeFrame() {
Timeline.startSync('Compositing', arguments: timelineWhitelistArguments);
try {
final ui.SceneBuilder builder = ui.SceneBuilder();
final ui.Scene scene = layer.buildScene(builder);
if (automaticSystemUiAdjustment)
_updateSystemChrome();
_window.render(scene);
scene.dispose();
assert(() {
if(debugRepaintRainbowEnabled || debugRepaintTextRainbowEnabled) debugCurrentRepaintColor = DebugCurrentRepaintColor. WithHue (360.0) (debugCurrentRepaintColor. Hue + 2.0) %.return true;
}());
} finally {
Timeline.finishSync();
}
}
Copy the code
So runApp created RenderView Flutter, and Window drawFrame method invokes the renderView.com positeFrame (); RenderView is the root node of the Flutter. The rootLayer it carries is a subclass of OffsetLayer TransformLayer, which is the root node of the Layer in Flutter.
Here is an example, as shown in the figure below is a simple non-standard code, after running the result is a blank black page, here we use the debugDumpLayerTree method to print the mechanism of Layer.
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
new Future.delayed(Duration(seconds: 1), () {
debugDumpLayerTree();
});
return MaterialApp(
title: 'GSY Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: Container(), //routes: routers, ); }}Copy the code
The result is printed as shown in the following LOG. As mentioned earlier, the TransformLayer acts as the rooterLayer and its owner is RenderView, and it has two child nodes: Child1 OffsetLayer and child2 PictureLayer.
By default there will be at least one OffsetLayer and PictureLayer due to the Layer formation mechanism (isRepaintBoundary automatically creates an OffsetLayer for ture) and Canvas drawing.
I/flutter (32494): TransformLayer#f8fa5
I/flutter (32494): │ owner: RenderView#2d51eI/flutter (32494) : │ creator: [root] I/flutter (32494) : │ offset: offset (0.0, 0.0) I/flutter (32494) : │ transform: I/flutter (32494) : │ [0] 2.8, 0.0, 0.0, 0.0 I/flutter (32494) : │ [1] of 0.0, 2.8, 0.0, 0.0 I/flutter (32494) : │ [2] of 0.0, 0.0, 1.0, 0.0 I/flutter (32494) : │ [3] of 0.0, 0.0, 0.0, 1.0 I/flutter (32494) : │ I/flutter (32494) : ├ ─ child 1: OffsetLayer#4503bI/ FLUTTER (32494): │ creator: RepaintBoundary ← _FocusMarker ← Semantics ← FocusScope I/flutter (32494): │ │ ← PageStorage ← Offstage ← _ModalScopeStatus ← I/flutter (32494): [LabeledGlobalKey │ │ _ModalScope < dynamic > - < _ModalScopeState < dynamic > >#e1be1]I/ FLUTTER (32494): │ ← overlayentry -[LabeledGlobalKey<_OverlayEntryState>Please # 95107]│ │ Overlay-[LabeledGlobalKey<OverlayState># ceb36] please..I/flutter (32494) : │ │ offset: offset (0.0, 0.0) I/flutter (32494) : │ │ I/flutter (32494) : │ └ ─ child 1: OffsetLayer#e8309I/ FLUTTER (32494): │ Creator: RepaintBoundary-[GlobalKey]# bbad8] please IgnorePointer pleaseI/flutter (32494): │ FadeTransition ← FractionalTranslation ← SlideTransition ← I/flutter (32494): │ _FadeUpwardsPageTransition please AnimatedBuilder please RepaintBoundary I/flutter (32494) : │ ← _FocusMarker ← Semantics ← FocusScope ← PageStorage ←... I/flutter (32494): │ offset: ├ ─ imp (2): └─ imp (2): └─ imp (3): garbage 2#be4f1I/ FLUTTER (32494): paint Bounds: Rect.fromLTRB(0.0, 0.0, 1080.0, 2030.0)Copy the code
According to the above LOG, first look:
OffsetLayer
的creator
是RepaintBoundary
And its source isOverlay
We know that Flutter can pass throughOverlay
Do global hover controls, whileOverlay
Is in theMaterialApp
的Navigator
, and it is a stand-aloneLayer
;- while
OffsetLayer
The child isPageStorage
,PageStorage
Is through theRoute
That is, the default route first page.
So now you know whyOverlay
Can be found inMaterialApp
All routes are displayed in global suspension.
The Scaffold was added to the original code as shown below and the debugDumpLayerTree was executed.
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
new Future.delayed(Duration(seconds: 1), () {
debugDumpLayerTree();
});
return MaterialApp(
title: 'GSY Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: Scaffold( body: Container(), ), //routes: routers, ); }}Copy the code
You can see that there’s a PhysicalModelLayer and a PictureLayer, PhysicalModelLayer is for setting shadows and things like that, After such as closing debugDisablePhysicalShapeLayers AppBar shadow will disappear, and after PictureLayer is also used for drawing.
I/flutter (32494): TransformLayer#ac14b
I/flutter (32494): │ owner: RenderView#f5eccI/flutter (32494) : │ creator: [root] I/flutter (32494) : │ offset: offset (0.0, 0.0) I/flutter (32494) : │ transform: I/flutter (32494) : │ [0] 2.8, 0.0, 0.0, 0.0 I/flutter (32494) : │ [1] of 0.0, 2.8, 0.0, 0.0 I/flutter (32494) : │ [2] of 0.0, 0.0, 1.0, 0.0 I/flutter (32494) : │ [3] of 0.0, 0.0, 0.0, 1.0 I/flutter (32494) : │ I/flutter (32494) : ├ ─ child 1: OffsetLayer#c0128I/ FLUTTER (32494): │ creator: RepaintBoundary ← _FocusMarker ← Semantics ← FocusScope I/flutter (32494): │ │ ← PageStorage ← Offstage ← _ModalScopeStatus ← I/flutter (32494): [LabeledGlobalKey │ │ _ModalScope < dynamic > - < _ModalScopeState < dynamic > >#fe143]I/ FLUTTER (32494): │ ← overlayentry -[LabeledGlobalKey<_OverlayEntryState># 9 cb60] please│ │ Overlay-[LabeledGlobalKey<OverlayState># ee455] please..I/flutter (32494) : │ │ offset: offset (0.0, 0.0) I/flutter (32494) : │ │ I/flutter (32494) : │ └ ─ child 1: OffsetLayer#fb2a6I/ FLUTTER (32494): │ creator: RepaintBoundary-[GlobalKey]# fd46b] please IgnorePointer pleaseI/flutter (32494): │ │ FadeTransition ← FractionalTranslation ← SlideTransition ← I/flutter (32494): │ │ _FadeUpwardsPageTransition please AnimatedBuilder please RepaintBoundary I/flutter (32494) : │ │ ← _FocusMarker ← Semantics ← FocusScope ← PageStorage ←... I/flutter (32494): │ │ offset: ├ ─ imp. 1, ├ ─ imp. 1, ├ ─ imp. 2, ├ ─ imp. 2, ├ ─ imp. 2, ├ ─ imp. 2, ├ ─ imp. 2, ├ ─ imp. 2, ├ ─ imp#f1460I/ FLUTTER (32494): │ creator: PhysicalModel ← AnimatedPhysicalModel ← Material ← I/flutter (32494): │ │ scaffoldScope ← Scaffold Semantics I/ FLUTTER (32494): │ │ ← Builder ← RepaintBoundary-[GlobalKey# fd46b] please IgnorePointer pleaseI/flutter (32494): │ │ FadeTransition ← FractionalTranslation ←... I/flutter (32494): │ │ elevation: 0.0 I/flutter (32494) : │ │ color: color (0 xfffafafa) I/flutter (32494) : │ │ I/flutter (32494) : │ └ ─ child 1: PictureLayer#f800fI/flutter (32494): │ paint bounds: I/flutter (32494): Child 2: └ ─ PictureLayer#af14dPaint Bounds: Rect.fromLTRB(0.0, 0.0, 1080.0, 2030.0) I/flutter (32494):Copy the code
PictureLayer, AnnotatedRegionLayer, and TransformLayer are added to the Layer tree by using Navigator to jump to another page and print the Layer tree on the new page. The AnnotatedRegionLayer is used to render the status bar at the top of a new page.
I/flutter (32494): TransformLayer#12e21
I/flutter (32494): │ owner: RenderView#aa5c7I/flutter (32494) : │ creator: [root] I/flutter (32494) : │ offset: offset (0.0, 0.0) I/flutter (32494) : │ transform: I/flutter (32494) : │ [0] 2.8, 0.0, 0.0, 0.0 I/flutter (32494) : │ [1] of 0.0, 2.8, 0.0, 0.0 I/flutter (32494) : │ [2] of 0.0, 0.0, 1.0, 0.0 I/flutter (32494) : │ [3] of 0.0, 0.0, 0.0, 1.0 I/flutter (32494) : │ I/flutter (32494) : ├ ─ child 1: OffsetLayer#fc176I/ FLUTTER (32494): │ creator: RepaintBoundary ← _FocusMarker ← Semantics ← FocusScope I/flutter (32494): │ │ ← PageStorage ← Offstage ← _ModalScopeStatus ← I/flutter (32494): [LabeledGlobalKey │ │ _ModalScope < dynamic > - < _ModalScopeState < dynamic > ># 43140]I/ FLUTTER (32494): │ ← overlayentry -[LabeledGlobalKey<_OverlayEntryState># 46 f19] please│ │ Overlay-[LabeledGlobalKey<OverlayState># af6f4] please..I/flutter (32494) : │ │ offset: offset (0.0, 0.0) I/flutter (32494) : │ │ I/flutter (32494) : │ └ ─ child 1: OffsetLayer#b6e14I/ FLUTTER (32494): │ creator: RepaintBoundary-[GlobalKey]# 0 ce90] please IgnorePointer pleaseI/flutter (32494): │ │ FadeTransition ← FractionalTranslation ← SlideTransition ← I/flutter (32494): │ │ _FadeUpwardsPageTransition please AnimatedBuilder please RepaintBoundary I/flutter (32494) : │ │ ← _FocusMarker ← Semantics ← FocusScope ← PageStorage ←... I/flutter (32494): │ │ offset: ├ ─ imp. 1, ├ ─ imp. 1, ├ ─ imp. 2, ├ ─ imp. 2, ├ ─ imp. 2, ├ ─ imp. 2, ├ ─ imp. 2, ├ ─ imp. 2, ├ ─ imp#4fdc6I/ FLUTTER (32494): │ creator: PhysicalModel ← AnimatedPhysicalModel ← Material ← I/flutter (32494): │ │ scaffoldscope ← SCAFFoldScope ← I/ SCAFFoldController (32494): │ │ ClipDemoPage ← Builder ← I/flutter (32494): │ RepaintBoundary-[GlobalKey]# 0 ce90] please IgnorePointer pleaseI/flutter (32494): │ │ I/flutter (32494): │ │ elevation: 0 I/flutter (32494): │ │ color: Color(0xffFafafa) I/flutter (32494): │ ├─ I/ Flutter (32494): │ ├─ Child 1: PictureLayer#6ee26│ ├ ─ paint bounds: I/flutter (0 folders, 1 folders, 2 folders): I/flutter (0 folders, 2 folders, 2 folders): I/flutter (0 folders, 2 folders): I/flutter (0 folders, 2 folders): Child 2: │ ├ ─ AnnotatedRegionLayer < SystemUiOverlayStyle >#cbeafI/flutter (32494) : │ │ │ value: {I/flutter systemNavigationBarColor: 4278190080, (32494) : │ │ │ systemNavigationBarDividerColor: null, statusBarColor: null, I/flutter (32494) : │ │ │ statusBarBrightness: Brightness. Dark, statusBarIconBrightness: I/flutter (32494) : │ │ │ Brightness, light, systemNavigationBarIconBrightness: I/flutter (32494): │ │ Brightness. Light} I/flutter (32494): │ │ size: size (32494) │ │ ├ ─ imp. 2, ├ ─ imp. 1, ├ ─ imp. 2, ├ ─ imp. 2, ├ ─ imp. 2, ├ ─ imp. 2, ├ ─ imp#edb15I/ FLUTTER (32494): │ │ Creator: PhysicalModel ← AnimatedPhysicalModel ← Material ← I/flutter (32494): │ │ ├ ─ AnnotatedRegion<SystemUiOverlayStyle> ← Semantics ← AppBar ← I/flutter (32494): │ │ FlexibleSpaceBarSettings ← ConstrainedBox ← MediaQuery ← I/flutter (32494): │ │ │ LayoutId-[<_ScaffoldSlot. AppBar >] ← CustomMultiChildLayout ← I/flutter (32494): │ │ │ AnimatedBuilder please... I/flutter (32494) : │ │ │ elevation: 4.0 I/flutter (32494) : │ │ │ color: MaterialColor (primary value: Color (0 xff2196f3)) I/flutter (32494) : │ │ │ I/flutter (32494) : │ │ └ ─ child 1: PictureLayer#418ce│ ├ ─ paint bounds: I/flutter (0 folders, 1 folders, 2 folders): I/flutter (0 folders, 2 folders, 2 folders): I/flutter (0 folders, 2 folders): I/flutter (0 folders, 2 folders): │ └ ─ child 3: TransformLayer#7f867│ │ folders: I/flutter (0 folders, 0 folders): I/flutter (0 folders, 2 folders): I/flutter (0 folders, 2 folders): I/flutter (0 folders, 2 folders): I/flutter (0 folders, 2 folders): I/flutter (0 folders, 2 folders): │ │ [0] 1.0, 0.0, 0.0, 0.0 I/flutter (32494) : │ │ [1] - 0.0, 1.0, 0.0, 0.0 I/flutter (32494) : │ │ [2] 0.0, 0.0, 1.0, 0.0 I/flutter (32494) : │ │ [3] of 0.0, 0.0, 0.0, 1.0 I/flutter (32494) : │ │ I/flutter (32494) : │ └ ─ child 1: PhysicalModelLayer#9f36bI/ FLUTTER (32494): │ creator: PhysicalShape ← _MaterialInterior ← Material ← I/flutter (32494): │ │ ConstrainedBox ← _FocusMarker ← Focus ← _InputPadding ← I/flutter (32494): │ │ Semantics ← RawMaterialButton ← KeyedSubtree-[GlobalKey#9ead9]I/flutter (32494): │ │ I/flutter (32494): │ │ elevation: 0 I/flutter (32494): │ │ color: │ ├ ─ imp. 1, ├ ─ imp. 2, ├ ─ imp. 2, ├ ─ imp. 2, ├ ─ imp. 3, ├ ─ imp#2a0742. I/flutter (32494): │ paint Bounds: I/flutter (32494): 2. Child 2: └ ─ PictureLayer#3d42dPaint Bounds: Rect.fromLTRB(0.0, 0.0, 1080.0, 2030.0) I/flutter (32494):Copy the code
So you can see that the widgets in a Flutter eventually form a variety of layers, each with its own regions and functions. For example, AnnotatedRegionLayer handles the color change of the status bar on a new page. These layers are eventually converted into EngineLayer through SceneBuilder, and finally submitted for Scene to be drawn by Engine.
To sum up: Before the Layer of the Flutter Framework can be drawn, it needs to be processed by SceneBuinlder to get an EngineLayer. The Layer in the Flutter Framework can be interpreted as the object encapsulation of “SceneBuinlder”, while “EngineLayer” is the real EngineLayer. The resulting Scene will be submitted to the Engine to draw.
From then on, canto XXI is finally over! (/ / / del / / /)
Resources to recommend
- Making: github.com/CarGuo
- Open Source Flutter complete project:Github.com/CarGuo/GSYG…
- Open Source Flutter Multi-case learning project:Github.com/CarGuo/GSYF…
- Open Source Fluttre Combat Ebook Project:Github.com/CarGuo/GSYF…
- Open Source React Native project: github.com/CarGuo/GSYG…