flutter layout和paint流程

新RenderObject的layout和paint

由以下RenderObject的attach方法源码可知,新RenderObject在attach的时候会被标记为需要layout和paint

//class RenderObject
@override
  void attach(PipelineOwner owner) {
    super.attach(owner);
    if (_needsLayout && _relayoutBoundary != null) {
      _needsLayout = false;
      markNeedsLayout();
    }
  ...
    if (_needsPaint && _layer != null) {
      _needsPaint = false;
      markNeedsPaint();
    }
 ...
  }
flutter_layout.png
flutter_paint.png

layout流程

  • markNeedsLayout : 是relayoutBoundary才会owner!._nodesNeedingLayout.add(this),否则尝试markParentNeedsLayout
  • flushLayout : 该方法中PipelineOwner对_nodesNeedingLayout中的RenderObject进行layout操作,
  • performLayout :RenderObject的该方法内会调用child的layout方法,layout方法内会调用markNeedsPaint方法,如果RenderObject是repaintBoundary,则添加到owner!._nodesNeedingPaint,如果不是repaintBoundary,则调起parent的markNeedsPaint方法。

paint流程

  • layout流程中已经将是repaintBoundary且需要repaint的RenderObject添加到owner!._nodesNeedingPaint,其他情况也可能调起markNeedsPaint将RenderObject添加到owner!._nodesNeedingPaint,不一定是layout过程中。
  • flushPaint :主要操作如下
  • 如果RenderObject的_layer为空,则创建OffsetLayer
  • 创建RenderObject对应的PaintingContext
  • 当RenderObject通过PaintingContext获取canvas进行实质性绘制的时候就会启动record(记录canvas的绘制,并在最后endRecord的时候生成图像)
  • 进行RenderObject或者其child的paint操作,由下面的部分源码可知,如果遇到child是RepaintBoundary,会提前stopRecord,并且在_compositeChild方法中将是RepaintBoundary的child的layer直接加到layer树中。
  • 将layer加到layer树中。
  • 将layer中的picture提交gpu进行渲染
  • 由上可知,isRepaintBoundary的RenderObject会有对应的layer,且两个isRepaintBoundary RenderObject之间的RenderObject会被绘制成一个picture。
class PaintingContext
/// Paint a child [RenderObject].
  ///
  /// If the child has its own composited layer, the child will be composited
  /// into the layer subtree associated with this painting context. Otherwise,
  /// the child will be painted into the current PictureLayer for this context.
  void paintChild(RenderObject child, Offset offset) {
  ...
    if (child.isRepaintBoundary) {
      stopRecordingIfNeeded();
      _compositeChild(child, offset);
    } else {
      child._paintWithContext(this, offset);
    }
...
  }
void _compositeChild(RenderObject child, Offset offset) {
    assert(!_isRecording);
    assert(child.isRepaintBoundary);
    assert(_canvas == null || _canvas!.getSaveCount() == 1);

    // Create a layer for our child, and paint the child into it.
    if (child._needsPaint) {
      repaintCompositedChild(child, debugAlsoPaintedParent: true);
    } else {
      assert(() {
        // register the call for RepaintBoundary metrics
        child.debugRegisterRepaintBoundaryPaint(
          includedParent: true,
          includedChild: false,
        );
        child._layer!.debugCreator = child.debugCreator ?? child;
        return true;
      }());
    }
    assert(child._layer is OffsetLayer);
    final OffsetLayer childOffsetLayer = child._layer as OffsetLayer;
    childOffsetLayer.offset = offset;
    appendLayer(child._layer!);
  }
class Layer
...
/// This layer's next sibling in the parent layer's child list.
  Layer? get nextSibling => _nextSibling;
  Layer? _nextSibling;

  /// This layer's previous sibling in the parent layer's child list.
  Layer? get previousSibling => _previousSibling;
  Layer? _previousSibling;
...

layer提交给gpu

flutter_layer.png

由上图可知,layer树提交给gpu流程如下:

  • RendererBinding的drawFrame方法中调用RenderView的compositeFrame方法
  • RenderView的layer执行buildScene方法
  • 遍历layer树,如果layer能复用(!_needsAddToScene && _engineLayer != null),则直接将_engineLayer传递给SceneBuilder,否则通过SceneBuilder的pushxxx方法创建EngineLayer
  • 通过SceneBuilder的build方法创建Scene对象
  • 将scene对象传递给Window的render方法。
//class ContainerLayer
@override
  void addToScene(ui.SceneBuilder builder, [ Offset layerOffset = Offset.zero ]) {
    addChildrenToScene(builder, layerOffset);
  }

  void addChildrenToScene(ui.SceneBuilder builder, [ Offset childOffset = Offset.zero ]) {
    Layer? child = firstChild;
    while (child != null) {
      if (childOffset == Offset.zero) {
        child._addToSceneWithRetainedRendering(builder);
      } else {
        child.addToScene(builder, childOffset);
      }
      child = child.nextSibling;
    }
  }

void _addToSceneWithRetainedRendering(ui.SceneBuilder builder) {
    if (!_needsAddToScene && _engineLayer != null) {
      builder.addRetained(_engineLayer!);
      return;
    }
    addToScene(builder);
    _needsAddToScene = false;
  }
//class Layer
void markNeedsAddToScene() {
    // Already marked. Short-circuit.
    if (_needsAddToScene) {
      return;
    }

    _needsAddToScene = true;
  }

你可能感兴趣的:(flutter layout和paint流程)