flutter 绘制源码解析

flutter 绘制源码解析,第1张

//绘制过程概述:在绘制过程中,渲染树会生成一个合成层树,这些层被上传到引擎并由合成器显示。

//Layer 是合成层树的一个切片,layer被排列成层次结构,每个节点都可能影响它下面的节点
在绘制的时候,会把每个绘制节点保存到Layer上面,
//最后合成树,创建一个SceneBuilder对象,根layer对象调用addToScene方法,SceneBuilder.build以获得一个Scene。然后可以使用dart:ui.FlutterView.render绘制场景。


RendererBinding
@protected
void drawFrame() {
  pipelineOwner.flushLayout();
  pipelineOwner.flushCompositingBits();
//开始绘制
  pipelineOwner.flushPaint();
  if (sendFramesToEngine) {
    renderView.compositeFrame(); // this sends the bits to the GPU
    pipelineOwner.flushSemantics(); // this also sends the semantics to the OS.
    _firstFrameSent = true;
  }
}
看回顾 flutter Widget、Element和RenderObject 树的插入源码分析
RenderView 插入树过程

void prepareInitialFrame() {
   scheduleInitialPaint(_updateMatricesAndCreateNewRootLayer());
     ...省略
}
TransformLayer _updateMatricesAndCreateNewRootLayer() {
  _rootTransform = configuration.toMatrix();
//创建根layer
  final TransformLayer rootLayer = TransformLayer(transform: _rootTransform);
//绑定渲染对象
  rootLayer.attach(this);
  return rootLayer;
}
void scheduleInitialPaint(ContainerLayer rootLayer) {
  _layerHandle.layer = rootLayer;
//添加自己到绘制节点 这里是根节点
  owner!._nodesNeedingPaint.add(this);
}


绘制

PipelineOwner

void flushPaint() {
  final List dirtyNodes = _nodesNeedingPaint;
    _nodesNeedingPaint = [];
    for (final RenderObject node in dirtyNodes
      ..sort((RenderObject a, RenderObject b) => b.depth - a.depth)) {
      if (node._needsPaint && node.owner == this) {
        if (node._layerHandle.layer!.attached) {
        //执行
          PaintingContext.repaintCompositedChild(node);
        } else {
          node._skippedPaintingOnLayer();
        }
      }
    }
}
PaintingContextstatic void _repaintCompositedChild(
  RenderObject child, {
  bool debugAlsoPaintedParent = false,
  PaintingContext? childContext,
}) {
//获取当前layer
  OffsetLayer? childLayer = child._layerHandle.layer as OffsetLayer?;
//创建新的
  if (childLayer == null) {
    final OffsetLayer layer = OffsetLayer();
    child._layerHandle.layer = childLayer = layer;
  } else {
//否则清空子layer
    childLayer.removeAllChildren();
  }
//RenderObject不是直接持有画布,而是使用PaintingContext进行绘画。PaintingContext有一个Canvas,它接收单独的绘制 *** 作,并且还具有绘制子渲染对象的功能。
  childContext ??= PaintingContext(childLayer, child.paintBounds);
  child._paintWithContext(childContext, Offset.zero);
  childContext.stopRecordingIfNeeded();
}

RenderObject

void _paintWithContext(PaintingContext context, Offset offset) {
//layout 时候已经为false.回顾请看 flutter widget layout测量源码解析
  if (_needsLayout)
    return;
//标记
  _needsPaint = false;
  try {
//开始绘制
    paint(context, offset);
  }
...省略
}
RenderView
@override
void paint(PaintingContext context, Offset offset) {
  if (child != null)
//子对象依次递归
    context.paintChild(child!, offset);
}
PaintingContext
void paintChild(RenderObject child, Offset offset) {
//以RepaintBoundary 为例  子部件是边界
  if (child.isRepaintBoundary) {
//停止录制, 把当前的 canvas 等值置为空
    stopRecordingIfNeeded();
    _compositeChild(child, offset);
  } else {
    child._paintWithContext(this, offset);
  }
}

//子部件不是边界的情况下

void _paintWithContext(PaintingContext context, Offset offset) {
  if (_needsLayout)
    return;
  _needsPaint = false;
  try {
//开始绘制
    paint(context, offset);
  }
}

//子部件是边界的情况下

void _compositeChild(RenderObject child, Offset offset) {
// 以RepaitBoundary 为例 
  if (child._needsPaint) {
//再次递归回到_repaintCompositedChild
  repaintCompositedChild(child, debugAlsoPaintedParent: true);
  } 
//获取边界的layer 
  final OffsetLayer childOffsetLayer = child._layerHandle
      .layer! as OffsetLayer;
  childOffsetLayer.offset = offset;
//添加子layer
  appendLayer(childOffsetLayer);
}
@protected
void appendLayer(Layer layer) {
/删除当前对象在父类的引用
  layer.remove();
//插入
  _containerLayer.append(layer);
}

@override
void adoptChild(AbstractNode child) {
//是否禁用渲染的保留
  if (!alwaysNeedsAddToScene) {
    markNeedsAddToScene();
  }

  super.adoptChild(child);
}
AbstractNode
void adoptChild(covariant AbstractNode child) {
//绑定当前layer
  child._parent = this;
  if (attached)
//子layer绑定根的渲染对象 保证子对象都拥有同一个owner 
    child.attach(_owner!);
//深度加一
  redepthChild(child);
}

再来看  markNeedsPaint

layout 测量的时候标记

RenderObject
void markNeedsPaint() {
  if (_needsPaint)
    return;
  _needsPaint = true;
  if (isRepaintBoundary) {
    if (owner != null) {
//是边界,就添加进去
      owner!._nodesNeedingPaint.add(this);
//请求更新
      owner!.requestVisualUpdate();
    }
  } else if (parent is RenderObject) {
    final RenderObject parent = this.parent! as RenderObject;
//递归调用父类,直到边界
    parent.markNeedsPaint();
  } else {
//直接请求刷新
    if (owner != null)
      owner!.requestVisualUpdate();
  }
}

具体paint 实现 ColoredBox 为例

@override
void paint(PaintingContext context, Offset offset) {
  if (size > Size.zero) {
//开始绘制
    context.canvas.drawRect(offset & size, Paint()..color = color);
  }
  if (child != null) {
    context.paintChild(child!, offset);
  }
}
@override
Canvas get canvas {
  if (_canvas == null)
    _startRecording();
  return _canvas!;
}

void _startRecording() {
//绘制保存的地方
  _currentLayer = PictureLayer(estimatedBounds);
  _recorder = ui.PictureRecorder();
//绘制的画布
  _canvas = Canvas(_recorder!);

//绘制的layer 保存到父layer下面
  _containerLayer.append(_currentLayer!);
}

//setstate 重绘时候 *** 作

void setState(VoidCallback fn) {
...省略
  _element!.markNeedsBuild();
}
void markNeedsBuild() {
  if (_lifecycleState != _ElementLifecycle.active)
    return;
  if (dirty)
    return;
//标记
  _dirty = true;
//添加标记元素脏, 在重建
  owner!.scheduleBuildFor(this);
}

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/990752.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存