OffsetLayer({ 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();
}
···
}
所以到这里 SceneBuilder
和 Layer
通过 EngineLayer
和 addToScene
方法成功关联起来,而 window.render
提交的 Scene
又是通过 SceneBuilder
构建得到,所以如下图所示, Layer
和 Scene
就这样“苟且”到了一起。
对面前面的蓝色小方块代码,如下代码所示,这里修改为使用 Layer
的方式实现,可以看到这样的实现更接近 Flutter Framework 的实现:通过 rootLayer
一级一级 append
构建出Layer
树,而 rootLayer
调用 addToScene
方法后,因为会执行 addChildrenToScene
方法,从而往下执行 child Layer
的 addToScene
。
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());
}
四、Layer 的品种
这里额外介绍下 Flutter 中常见的 Layer
,如下图所示,一般 Flutter 中 Layer
可以分为 ContainerLayer
和非 ContainerLayer
。
ContainerLayer
是可以具备子节点,也就是带有 append
方法,大致可以分为:
- 位移类(
OffsetLayer
/TransformLayer
); - 透明类(
OpacityLayer
) - 裁剪类(
ClipRectLayer
/ClipRRectLayer
/ClipPathLayer
); - 阴影类 (
PhysicalModelLayer
)
为什么这些 Layer
需要是 ContainerLayer
?因为这些 Layer
都是一些像素合成的操作,其本身是不具备“描绘”控件的能力,就如前面的蓝色小方块例子一样,如果要呈现画面一般需要和 PictureLayer
结合。
比如
ClipRRect
控件的RenderClipRRect
内部,在pushClipRRect
时可以会创建ClipRRectLayer
,而新创建的ClipRRectLayer
会通过appendLayer
方法触发append
操作添加为父Layer
的子节点。
而非 ContainerLayer
一般不具备子节点,比如:
PictureLayer
是用于绘制画面,Flutter 上的控件基本是绘制在这上面;TextureLayer
是用于外界纹理,比如视频播放或者摄像头数据;PlatformViewLayer
是用于 iOS 上PlatformView
相关嵌入纹理的使用;
举个例子,控件绘制时的 Canvas
来源于 PaintingCo