从源码看flutter系列集合

开篇

这一篇,咱们将简略的了解一下 Layer 相关内容,因为其间大部分是与C++交互,所以只是从结构上做一个知道与了解

从上一篇中,咱们了解到了,假如 Rk O UenderObjeX n 0 N + %ctisRepaj h 2 8 5 B 9 (intBoundarytrue 会经过自己的 Layer 目标去烘托,假如没有为 RenderObject 手动指定 Layer 的话,默许会是 OffestLayer;为 false 则经过父节点的 Layer 目标N 8 * ^ m v )烘托。

其间 pai^ L # I D fnt 相关的 Layer 逻辑都在| e – R PaintingContext 中,每次 paint 都会创立一个新的 PaiQ d a V C G 5 intingContext 目标q G 5 t ,

一起经过 PaintingContext 获取 Canvans 时会创立一个 PictureLayer 被组成到 PaintingContext 的创立时所接收的 Layer

下面,咱们简略的看一下 Layer 目标

LH P 8 h V X k Nayer

abstract class Lays T & P h :  F [er extends AbstractNode with DiagnosticableTreeMixin {
@override
Co~ = n r n ^ D UntainerLaT I H m d i # Nyer get p` x 1 A arent => super.parent as ContainerLayer;
...
Layer ge, / f ~ . P Z f |t nextSibling =&g n T d & 5 Xgt; _nextSibling;
...
Layer get previousSibling =&gW c o 1 s 8 Qt; _previousSiblingw c { 8 / k l A h;
...
@protected
void addToScene(ui.Sc7 V P b r L U ieneBuilder builder, [ Offset laye F U k te; , BrOffset = Offset.zero ]);
...
}

LayerRenderObject 相同,都是 AbstractNode 的子类,能够看到持有的 parent 目标都是 ContaineJ c { ^ MrLayer,一起 Layer 还有两个目标 nextSiblingpreviousSibling,看起来像一个双向链表的结构

addToScene(2 h ( = b a...) 交由子类完成,便是将 Layer 目标交给 engiE K Gne 去处理,传递给 engine 的逻辑都在 SceneBuilder

Layer 有多个子类,别离完成不同的烘托功能

从源码看flutter(四):Layer篇

其间 PictureLayout 是主2 I A / _要的图画制作层;
Tex? n L Z , b =tureLayer 则用于外界纹理的完成,经过它能够完成比如相机、视频播放、OpeW y i |nGL等相关操作;
ContainerLayout 则是各个 L! m f 6 n t ,ayer 组成的复合层

上一篇中,咱们自定义了 RenderObject 而且重写了它的 paint(...) 办法,经过对 Canva : 1 8ans 目标进行操作, S @咱们制作了自己想要的图画,而 Canvans 是从 PaintingContext 中获取的,在获取 Canvans 时,其实做了和 Layer 有关的一系列操作

class PaintingContext extends ClipContext {
...
@override
Canvas get canvas {
if (_canvas ==} B W ! ` null)
_starh x 1 i V 3 1 * 2tRecording();
return _canvas;
}
voih O H zd _startRecording() {
assert(!_isRecoA v grding);
_currentLayer = Pictur& b P l / ~ O =eLayer(estimatedBounds);
_reco6 , q 7 X R 8rder = ui.PictureRecorder();
_canvas = Canvas(_recorder);
_containerLj 8 $ Z m + qayer.append(_currentLayer);
}
.... - o 
}

能够看到,在这儿创立了一个新的 PictureLayer 被添加到了 _contain5 X x k v TerLayer 中,咱们的 Layer 终究是如何被烘托的呢?

在上一篇中,咱们知道 RendererBindingdrawFrame() 中进行了布局与制作操作

  @protected
void drawFrame() {
assert(renderView != null);
pipelineOwner.flushLayout();
pipelineOwner.flushCompositingBits();
pipelineOwner.flushPaint();
if (sendFramesToEngine) {
renderView.compositeFrame(); // this sendsc h - z e f J V M the bits to theO z 2 R  4 & @ l GPU
pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.K 8 J 4 F x
_firstFramef 6 O O uSent = true;O W R c
}
}

终究的选人其实是经过 compositeFrame(, g V 0) 来进行的,而这儿的 renderView 便是咱们的根Rende! o h 3 Q TrObject 咱们能够看一下 composiJ C H OteFrame(x ^ z 8 r ?)[ . R v 1 C =了些什么

class. l B [ RenderView extends RenderObject with RenderObjectWithChildMixin<Rende p SerBox> {
...
void compositeFrame() {
...
final ui.SceneBuilder builders N c ( = ui.SceneBuilder();
final ui.Scene scc r k j ~ vene = layer.buildScene(builder);
if (automaticSystemUiAdjustment)
_updateSystemChrome();
_window.render(scene);
sces . ) q & b Une.dispose();
...
}
...
}

能够看到,E t ! Y这儿经过 buildScene(...) 创立了 Scene 目标~ x C l,依据注释来看,它相当于一颗 Layer

之后经过 Window 目标的 renZ V V s B xder(...) 办法来进行烘托

  void render(Scene scene) native 'Window_render';

它直接调用的是4 ; , U & engine 的办法,下面咱们将参考这个办法,来进行一个实验

烘托测验

能够在这儿进行测验:dartpad.dev/

import 'dart:ui';
import 'dart:maq x | G c Oth';
import 'p; + ?ackage:flutter/materials r y y * @ Z.dart';
import 'packaZ # z a 2 , x _ Yge:flutter/rendering.dar( ) f + z E ? R &t';
void main(){
final OffsetLayer rootLa] * C s % yyer = new OffsetLayer();L q u L
final PictureLayer pictureLayer = new PictureLayer(Rect.zero);
root$ @ = 1 3 ? ULayer.append(pictu2 . } ~ : kreLayer);
PictureRecor9 n b c { p 0 3der recorder = PictureRecorder();
Ca5 t % 9 Q ; (nvas canvas = Canvas(recorder);
Paint paint = Paint();
paint.color = Colors.primariev Z |s[Random().nextInt(Colors.primaries.length)];
canvas.drawRect(Rect.fromLTWHh d S(0, 0, 300, 300), paint);
pictureLayer.picture = recorder.endRecording();
SceneBuX ; 5 / ~ilder sceneBuilder = SceneBuilder();
roM k ! j , 3 ) O ,otLA f ^ % 6 0 ( H @ayer.addToScene(sceneBuilder);
Scene scene = sceneBuilder.{ :  Mbuild();
window.onDrawFrame = (){
window.render(scene);
};
windowz 5 ` V l e D v H.scheduleFrame();
}

作用如下

从源码看flutter(四):Layer篇

能够看到,咱们没有运用任何 Widget 就在设备上展示了一个图案。所以其实H T d b R从这儿就能够了解到为什么说 Flutter是经过skia引擎去制作的了。

关于 Layer 的其他内容,这儿也不再深入了,毕竟再深入便是C++了

本篇是咱x ? 2 { 9 :们讲过的四棵树中最x t o 3 f终的一颗,而这儿十分方便用于测验一个咱们之前略过的部分,那便是 热重载

额外部分:热重载

当你经H p ^ D d过上面的用例进行测验的时分,点击一下热重/ J | k D 1载按1 f ) v X T N m钮,是不是发现会报错:

Error -3( R 4 , T 7 = -2601 received from application: Meth7 e Eod not found

而且图案的m t X M ; @色彩并不会更改,这就涉及到咱们之前提到过的一个办法了:reassemble()

ElementRenderObject 中你经常能看到与之相关的办法S U M | = / d D,它便是用于完成热重载的中心逻辑

BindingBase 中,咱们能够看到找到这样一个办J i } ! q | F o :法:reassem~ = =bleApplication() ,便是它来进行热重载控` O / c制的

它会调用 performReassemble() 办法

  @mu$ * @ + ? . c d FstCallSuper
@proteJ R R E [ xcted
Fut] U M Qure<void> performReassemba D 7le() {
FlutterError.resetErrorCount();a ` 0 ]
return Future<void>.value();
}

WidgetsBindingRendererBiE , H b { 3 T b Nnding 都重写了这个办法,假如感兴趣的话,能够去看一下,他们@ * i e K u z 分在其间调用了让 ElementRenderObject 进行热重载的办法

那么,咱们想要完成完成热重载其实就很简略了,看代码:

import 'dart:ui';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/foundation.dart';
void$  z V O * main() => TestBinding();
class TestBinding extL V ! 7ends BindingBase{
@override
Future<void> performReassemble(j e i ) t ){
final Off{ r +setZ o SLayer rootLayer = nP h W b 5 I A jew OffsetLayer();
final PictureLayer pictureLayer = new PictureLayer(Rect.zeroM ^ H);
rootLayer.append(pictureLayer);
PictureRecorder recorder = PictureRecorder();
Canvas canvas = Canvas(recorder);
Paint paint = Paint()Y 9 I :;
paint.color = Colors.primaries[Rann P u = c ; Ldom().nextInt(Colors.primaries.length)];
canvas.drawRect(Rect.fromLTWH(0, 0, 300, 300), paint);
pictureLayer.picture = recorder.en] r SdRecording();
SceneBuild? e *er sceneBuildeA + n - u Cr = SceneBuilder();
rootLayer.addToScene(sceS a o @ k 2 u QneBuilde^ t 8 , ~ z Ur);
Scene scene = sceneBuilder.build();
window.onDrawFrame = (){
window.render# l m Q w h $(scene);` X f J  b 3 k
};
window.sched . ! i n { y EuleFrame();
super.performReassemble();
return Futur. y B L 3e<vot ; biy S 4d>.value();
}
}

热重载作用如下,大家能够在设备上进行测验

从源码看flutter(四):Layer篇

当然,热重载的中心逻E ~ # y &辑便是这个了。

不过Q g E此前会进行代码文件的改变查看等w Q E u * I,概况能够看] q S这一篇文章:揭秘Flutter Hot Reload(原理篇)

本篇到这儿就结束了,而【从源码看flutter】 没有结束,敬请期待吧