6、Paint 绘制(1)

1、Flutter 之图像绘制原理node

2、Widget、Element、RenderObjectweb

3、Flutter UI 更新流程canvas

4、build 流程分析bash

5、layout 流程分析框架

7、Paint 绘制(2)ide

8、composite 流程分析函数

9、Flutter 小实践post

一、分层绘制

相似web 端 canvas, 咱们常常是采用分层的策略 例如如下游戏场景, 在打斗的过程当中, 人物动做, 位移,动画等变化的频率和幅度是很大的,而背景变化的频率或幅度则相对较小(基本不变,或者缓慢变化,或者仅在某些时机变化),这个过程须要很频繁地更新和重绘人物,可是对于背景,咱们也许只须要绘制一次,也许只须要隔一段时间才重绘一次动画

若是只在一个画布里面绘制,那人物的的频繁变化也会引发背景的绘制,所以须要须要生成多个画布独立绘制,最后再合成ui

在flutter 中, 也是采用分层绘制的概念,例以下图,是Flutter框架渲染机制的一个示意图~ 在框架渲染完成以后会输出 的 一个个的 layer 造成的 layer tree,layer tree被送入engine,engine会把layer tree调度到GPU线程,在GPU线程内合成(compsite)layer tree,而后由Skia 2D渲染引擎渲染后送入GPU显示~

二、Layer 类

(1) Layer

abstract class Layer extends AbstractNode with DiagnosticableTreeMixin {
 
  @override
  ContainerLayer get parent => super.parent; 
  Layer get previousSibling => _previousSibling;
  Layer _previousSibling;
}
复制代码

类Layer是一个树形结构, 属性parent表明其父节点, nextSibling和previousSibling表示同一图层的前一个和后一个兄弟节点,即图层孩子节点们是用双向链表存储的

(2)AbstractNode

class AbstractNode {
  int get depth => _depth;
  int _depth = 0;
  void redepthChildren() { }
  Object get owner => _owner;
  Object _owner;

  /// The parent of this node in the tree.
  AbstractNode get parent => _parent;
  AbstractNode _parent;
  void adoptChild(covariant AbstractNode child) {}
  void dropChild(covariant AbstractNode child) {}
}
复制代码

Layer 继承 AbstractNode,所以ayer 也是一个个普通的节点,这个节点能够是叶子节点,也能够拥有子节点

三、Layer 分类

Layer 有不一样的实现类,只有ContainerLayer类型及其子类的图层能够拥有孩子,其余类型的Layer子类都是叶子图层。

四、绘制流程 layer 管理

分层绘制的核心思想是实现多个 canvas, 那在 flutter 里面,何时会建立新的 canvas? needsCompositing isRepaintBoundary

咱们先看 needsCompositing 在监听 Vsync 信号调用 drawFrame, (1) drawFrame

@protected
void drawFrame() {
  pipelineOwner.flushLayout();
  pipelineOwner.flushCompositingBits();
  pipelineOwner.flushPaint();
  renderView.compositeFrame(); // this sends the bits to the GPU
  pipelineOwner.flushSemantics(); // this also sends the semantics to
}
复制代码

在调用 flushPaint 进行绘制以前,会先调用 flushCompositingBits

(2) flushCompositingBits

void flushCompositingBits() {
  _nodesNeedingCompositingBitsUpdate.sort((RenderObject a, RenderObject b) => a.depth - b.depth);
  for (RenderObject node in _nodesNeedingCompositingBitsUpdate) {
    if (node._needsCompositingBitsUpdate && node.owner == this)
      node._updateCompositingBits();
  }
  _nodesNeedingCompositingBitsUpdate.clear();
}
复制代码

这个函数中,主要是遍历 _nodesNeedingCompositingBitsUpdate 节点集合,调用 _updateCompositingBits

(3) _updateCompositingBits

void _updateCompositingBits() {
  if (!_needsCompositingBitsUpdate)
    return;
  final bool oldNeedsCompositing = _needsCompositing;
  _needsCompositing = false;
  visitChildren((RenderObject child) {
    child._updateCompositingBits();
    if (child.needsCompositing)
      _needsCompositing = true;
  });
  if (isRepaintBoundary || alwaysNeedsCompositing)
    _needsCompositing = true;
  if (oldNeedsCompositing != _needsCompositing) {
    // 若是 oldNeedsCompositing != _needsCompositing, 则说明节点所在的图层发生了改变,则须要从新绘制
    markNeedsPaint();
  }
  _needsCompositingBitsUpdate = false;
}
复制代码

在这个函数中,遍历子节点,若是子节点 的 needsCompositing 为true, 则须要将该节点的 needsCompositing 设置为 true

上述代码 (2) 中,_nodesNeedingCompositingBitsUpdate 节点集合怎么来的? 追踪代码、则发如今 markNeedsCompositingBitsUpdate 函数中有相关处理

(4) markNeedsCompositingBitsUpdate

void markNeedsCompositingBitsUpdate() {
  if (_needsCompositingBitsUpdate)
    return;
  _needsCompositingBitsUpdate = true;
  if (parent is RenderObject) {
    final RenderObject parent = this.parent;
    if (parent._needsCompositingBitsUpdate)
      return;
    if (!isRepaintBoundary && !parent.isRepaintBoundary) {
      parent.markNeedsCompositingBitsUpdate();
      return;
    }
  }
  if (owner != null)
    owner._nodesNeedingCompositingBitsUpdate.add(this);
}
复制代码

在该代码段中会将该 renderObject 加入 _nodesNeedingCompositingBitsUpdate 集合中,同时向上遍历父节点的 markNeedsCompositingBitsUpdate 方法,

(5)markNeedsCompositingBitsUpdate 什么时候调用? renderObject 通常在 添加,删除孩子时调用 markNeedsCompositingBitsUpdate

//添加孩子
@override
void adoptChild(RenderObject child) {
  markNeedsCompositingBitsUpdate();
}

//删除孩子
@override
void dropChild(RenderObject child) {
  super.dropChild(child);
  markNeedsCompositingBitsUpdate();
}
复制代码

needsCompositing有哪些应用场景

(6) needsCompositing

在绘制时,若是 needsCompositing 这个属性值 为 true, 则意味着须要新增一个 layer

ClipRectLayer pushClipRect(bool needsCompositing, Offset offset, Rect clipRect, PaintingContextCallback painter, { Clip clipBehavior = Clip.hardEdge, ClipRectLayer oldLayer }) {
  final Rect offsetClipRect = clipRect.shift(offset);
  if (needsCompositing) {
    final ClipRectLayer layer = oldLayer ?? ClipRectLayer();
    layer
      ..clipRect = offsetClipRect
      ..clipBehavior = clipBehavior;
    pushLayer(layer, painter, offset, childPaintBounds: offsetClipRect);
    return layer;
  } else {
    clipRectAndPaint(offsetClipRect, clipBehavior, offsetClipRect, () => painter(this, offset));
    return null;
  }
}
复制代码
相关文章
相关标签/搜索