if (!_needsLayout && constraints == _constraints) { if (relayoutBoundary != _relayoutBoundary) { //如果布局边界发生了变化,则递归访问子孙组件,将子孙的_relayoutBoundary设置为新的布局边界; //递归终止条件是,子孙组件自身就是边界节点。 _relayoutBoundary = relayoutBoundary; visitChildren(_propagateRelayoutBoundaryToChild); } return; } _constraints = constraints; if (_relayoutBoundary != null && relayoutBoundary != _relayoutBoundary) { // The local relayout boundary has changed, must notify children in case // they also need updating. Otherwise, they will be confused about what // their actual relayout boundary is later. //递归清除子孙组件的_relayoutBoundary,递归终止条件是子孙组件自身就是边界节点 visitChildren(_cleanChildRelayoutBoundary); } _relayoutBoundary = relayoutBoundary;
void markNeedsPaint() { if (_needsPaint) { return; } _needsPaint = true; // If this was not previously a repaint boundary it will not have // a layer we can paint from. if (isRepaintBoundary && _wasRepaintBoundary) { // If we always have our own layer, then we can just repaint // ourselves without involving any other nodes. assert(_layerHandle.layer is OffsetLayer); if (owner != null) { //当前节点是绘制边界节点,把边界节点加入到重绘列表中 owner!._nodesNeedingPaint.add(this); owner!.requestVisualUpdate(); //idle或postFrameCallbacks阶段会调用scheduleFrame,其他阶段无作用 } } elseif (parent is RenderObject) { //递归调用parent,直到遇到绘制边界节点 parent!.markNeedsPaint(); } else { // If we are the root of the render tree and not a repaint boundary // then we have to paint ourselves, since nobody else can paint us. // We don't add ourselves to _nodesNeedingPaint in this case, // because the root is always told to paint regardless. // // Trees rooted at a RenderView do not go through this // code path because RenderViews are repaint boundaries. if (owner != null) { owner!.requestVisualUpdate(); } } }
// Sort the dirty nodes in reverse order (deepest first). for (final RenderObject node in dirtyNodes..sort((RenderObject a, RenderObject b) => b.depth - a.depth)) { //能够加入_nodesNeedingPaint肯定都是绘制边界节点 if ((node._needsPaint || node._needsCompositedLayerUpdate) && node.owner == this) { if (node._layerHandle.layer!.attached) { assert(node.isRepaintBoundary); if (node._needsPaint) { PaintingContext.repaintCompositedChild(node); //内部直接调用_repaintCompositedChild } else { PaintingContext.updateLayerProperties(node); } } else { node._skippedPaintingOnLayer(); } } } for (final PipelineOwner child in _children) { child.flushPaint(); } } finally { ... } }
//PaintingContext的静态函数 staticvoid _repaintCompositedChild( RenderObject child, { bool debugAlsoPaintedParent = false, PaintingContext? childContext, }) { assert(child.isRepaintBoundary); //必须是绘制边界节点 OffsetLayer? childLayer = child._layerHandle.layer as OffsetLayer?; if (childLayer == null) { // 为这个绘制边界节点创建一个OffsetLayer,也有可能是OffsetLayer的子类 final OffsetLayer layer = child.updateCompositedLayer(oldLayer: null); child._layerHandle.layer = childLayer = layer; } else { childLayer.removeAllChildren(); //childLayer不为空的情况,此处返回的必须还是childLayer,后面有个assert来检查 final OffsetLayer updatedLayer = child.updateCompositedLayer(oldLayer: childLayer); assert(identical(updatedLayer, childLayer), '$child created a new layer instance $updatedLayer instead of reusing the ' 'existing layer $childLayer. See the documentation of RenderObject.updateCompositedLayer ' 'for more information on how to correctly implement this method.' ); } child._needsCompositedLayerUpdate = false;
assert(identical(childLayer, child._layerHandle.layer)); assert(child._layerHandle.layer is OffsetLayer); //必须是OffsetLayer
// Double-check that the paint method did not replace the layer (the first // check is done in the [layer] setter itself). assert(identical(childLayer, child._layerHandle.layer)); childContext.stopRecordingIfNeeded(); }
//RenderObject void _paintWithContext(PaintingContext context, Offset offset) { // If we still need layout, then that means that we were skipped in the // layout phase and therefore don't need painting. We might not know that // yet (that is, our layer might not have been detached yet), because the // same node that skipped us in layout is above us in the tree (obviously) // and therefore may not have had a chance to paint yet (since the tree // paints in reverse order). In particular this will happen if they have // a different layer, because there's a repaint boundary between us. if (_needsLayout) { return; } RenderObject? debugLastActivePaint; _needsPaint = false; _needsCompositedLayerUpdate = false; _wasRepaintBoundary = isRepaintBoundary; try { //RenderObject执行paint进行绘制,需要子类来实现paint方法 paint(context, offset); assert(!_needsLayout); // check that the paint() method didn't mark us dirty again assert(!_needsPaint); // check that the paint() method didn't mark us dirty again } catch (e, stack) {... } }
//RenderShiftedBox void paint(PaintingContext context, Offset offset) { final RenderBox? child = this.child; if (child != null) { final BoxParentData childParentData = child.parentData! as BoxParentData; context.paintChild(child, childParentData.offset + offset); } }