Mastering Repaint Boundaries

Mastering Repaint Boundaries
Photo by Steve Johnson / Unsplash

Frequent changes to a widget's position, color, size, or children require rendering of new frames, which can degrade performance, especially in animations. In such cases, RepaintBoundary comes to our help.

Painting Phase

To understand how repaint boundary works and what problem it solves, I need to tell about the painting phase from the rendering pipeline.

Render pipeline sequencing
diagram

During the painting phase, graphic operations are recorded on corresponding layer. If the render object does not have a layer, it records operations on the parent layer. Painting a child render object on the parent layer will cause the parent to be repainted, traversing until the next repaint boundary is reached.

💡
During the paint phase, rather than directly rendering anything, Flutter's rendering engine records the painting commands into a display list (or a picture). These commands include drawing primitives like lines, circles, text, images, and paths.

Repaint Boundary

A RepaintBoundary is a special marker in the render tree that tells Flutter to limit the painting area. When a widget is wrapped with a RepaintBoundary, a new layer is created in the rendering engine, isolating itself and its children from the rest of the tree.

Therefore, any repaints that happen inside the repaint boundary will not trigger repaints to other widgets in the application. Conversely, if the widgets outside are repainted, the content inside the repaint boundary won't be affected.

💡
Even a small paint change can potentially affect a large portion of the tree. For example, CircularProgressIndicator can cause the entire tree to be repainted.

The video demonstrates how repaint boundaries work. Using Flutter DevTools, we can effectively debug repaints and observe these boundaries in action. Initially, the entire screen was repainted due to the absence of a repaint boundary. However, after introducing a repaint boundary, only the specific area within that boundary was repainted.

Why do paints spread upward?

Paints spread upward because of the way elements are layered and interact with each other. When there's no clear boundary separating these layers, everything gets painted together.

So, if you need to update or repaint one object, this lack of separation means you might unintentionally affect adjacent objects. It's similar to drawing on a single transparent sheet - changing one part can alter the entire sheet's appearance.

In complex UIs with overlapping widgets and effects, ensuring consistency becomes crucial. Thus, a repaint on one element can lead to a chain reaction, where multiple connected elements need to be repainted to maintain the overall visual harmony.

OffsetLayer

OffsetLayer is a type of ContainerLayer used in Flutter's rendering engine to apply an offset to the layer during the composition phase. Essentially, an OffsetLayer applies a translation in 2D space to any rendering performed by its child layers.

When a RenderObject declares itself as a repaint boundary, the framework assigns it an OffsetLayer, effectively encapsulating its paint information. This encapsulation allows the engine to potentially optimize repainting of widgets, since only the layers that have changed need to be repainted and reassembled.

Caching: The OffsetLayer allows the rendered output of the subtree to be cached. If nothing changes within the repaint boundary, the cached output can be used directly in the next frame without repainting and re-compositing the entire subtree.

Offset layers play a key role in efficient repainting. When a rendering object acting as a repaint boundary is requested to paint at a particular offset within a PaintingContext, it first determines whether it needs to be repainted. If repainting is not necessary, it uses its existing OffsetLayer (along with its entire subtree) by modifying its Offset property, thereby truncating the paint walk.

Repaint Boundary Metrics

The render object associated with Repaint Boundary holds useful metrics which can tell you whether particular Repaint Boundary is efficient or not. See:

Finally

Consider supporting me by subscribing to my telegram channel and LinkedIn to not to miss exciting things about Dart & Flutter.