RepaintBoundary class
A widget that creates a separate display list for its child.
一个能够为 child 创建一个独立的display list 的widget。
This widget creates a separate display list for its child, which can improve performance if the subtree repaints at different times than the surrounding parts of the tree.
当使用RepaintBoundary widget为 child(子树) 创建独立的display list ,如果子树在与树的父容器等部分在不同的时间repaint,则可以提高性能。
This is useful since RenderObject.paint may be triggered even if its associated Widget instances did not change or rebuild. A RenderObject will repaint whenever any RenderObject that shares the same Layer is marked as being dirty and needing paint (see RenderObject.markNeedsPaint), such as when an ancestor scrolls or when an ancestor or descendant animates.
这很有用,因为 RenderObject.paint 很有可能会被触发,即使其关联的 Widget 实例没有更改或rebuild。 每当共享同Layer的任何 RenderObject 被标记为dirty且需要rebuild时,(该Layer下所有的)RenderObject 都会rebuild(请参阅 RenderObject.markNeedsPaint),例如当祖先widget滚动、祖先widget animate 、后代widget animate 等情况下。
Containing RenderObject.paint to parts of the render subtree that are actually visually changing using RepaintBoundary explicitly or implicitly is therefore critical to minimizing redundant work and improving the app’s performance.
因此,将 RenderObject.paint 包含到render子树的某些部分,这些部分实际上是使用 RepaintBoundary 显式或隐式地在视觉上发生变化,这对于最大限度地减少冗余工作和提高应用程序的性能至关重要。
When a RenderObject is flagged as needing to paint via RenderObject.markNeedsPaint, the nearest ancestor RenderObject with RenderObject.isRepaintBoundary, up to possibly the root of the application, is requested to repaint. That nearest ancestor’s RenderObject.paint method will cause all of its descendant RenderObjects to repaint in the same layer.
当通过 RenderObject.markNeedsPaint 将 RenderObject 标记为需要 paint时,将会向上遍历最近的具有 RenderObject.isRepaintBoundary 的祖先 RenderObject,直到可能是app的root,都被请求repaint。 最接近祖先的 RenderObject.paint 方法将导致其所有后代 RenderObject 在同Layer中repaint。
RepaintBoundary is therefore used, both while propagating the markNeedsPaint flag up the render tree and while traversing down the render tree via PaintingContext.paintChild, to strategically contain repaints to the render subtree that visually changed for performance. This is done because the RepaintBoundary widget creates a RenderObject that always has a Layer, decoupling ancestor render objects from the descendant render objects.
因此,在将 markNeedsPaint 标志向上传播render树以及通过 PaintingContext.paintChild 向下遍历render树时都使用了 RepaintBoundary,以策略性地包含对渲染子树的重绘,这些渲染子树在视觉上会因性能而发生变化。 这样做是因为 RepaintBoundary widget创建了一个始终自带Layer的 RenderObject,从而将祖先renderObject与后代renderObject解耦。
RepaintBoundary has the further side-effect of possibly hinting to the engine that it should further optimize animation performance if the render subtree behind the RepaintBoundary is sufficiently complex and is static while the surrounding tree changes frequently. In those cases, the engine may choose to pay a one time cost of rasterizing and caching the pixel values of the subtree for faster future GPU re-rendering speed.
如果 RepaintBoundary 包含的render子树足够复杂并且是静态的,而周围的渲染树经常变化,那么 RepaintBoundary 可能会向引擎暗示它应该进一步优化animation性能的进一步副作用。 在这些情况下,引擎可能会选择一次性支付raster和缓存子树的像素值的成本,以实现更快的即将到来的 GPU 重新渲染的速度。
Several framework widgets insert RepaintBoundary widgets to mark natural separation points in applications. For instance, contents in Material Design drawers typically don’t change while the drawer opens and closes, so repaints are automatically contained to regions inside or outside the drawer when using the Drawer widget during transitions.
几个framework widget插入 RepaintBoundary widget以标记app程序中的自然分隔点。 例如,Material Design drawer中的内容通常不会在drawer打开和关闭时更改,因此在转换期间使用 Drawer widget时,repaint会自动包含在抽屉内部或外部的区域中。
See also:
也可以看看:
debugRepaintRainbowEnabled, a debugging flag to help visually monitor render tree repaints in a running app.
debugRepaintRainbowEnabled,一个调试标志,用于帮助直观地监控正在运行的应用程序中的render树的repaint。
debugProfilePaintsEnabled, a debugging flag to show render tree repaints in the observatory’s timeline view.
debugProfilePaintsEnabled,一个调试标志,用于在observatory时间线视图中显示render树的repaint。
译者推荐:可以阅读《Flutterl实战》的Flutter 绘制原理