The Magic of Repaint Boundary!

Prashant Gupta
4 min readJan 5, 2025

--

What is a RepaintBoundary?

A RepaintBoundary is like a boundary or fence for a widget and its children. It separates their rendering process into its own layer. This means when something inside the boundary changes, only that part gets repainted instead of the entire surrounding UI.

Basically, it helps avoid unnecessary redrawing of larger parts of the screen when only a small change occurs.

For a quick visual overview of RepaintBoundary, check out this 2-minute video to get started.

https://www.youtube.com/embed/cVAGLDuc2xE?si=44qgEKhmExZnnDSH

💡 A Pro Tip:- debugRepaintRainbowEnabled flag

A debugging flag to help visually monitor render tree repaints in a running app.

Overlay a rotating set of colours when repainting layers in debug mode.

Explore with Flutter Docs

void main() {
debugRepaintRainbowEnabled=true;
runApp(const MyApp());
}

Let’s check the behaviour of the RepaintBoundary with a Example

SingleChildScrollView(
child: Column(
children: [
for (int i = 0; i < 50; i++)
Column(
children: [
Card(
elevation: 4,
margin: const EdgeInsets.all(16),
child: Container(
width: 200,
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CircleAvatar(
radius: 40,
backgroundColor: Colors.grey[300],
child: Icon(Icons.person,
size: 40,
color: Colors.grey[700]
),
),
const SizedBox(height: 16),
Text('John Doe $i'),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () => setState(() => isLoading = !isLoading),
child: Text(
isLoading ?
'Stop Loading' :
'Start Loading'),
),
],
),
),
),
if (isLoading)
// Animation affecting the entire tree
CircularProgressIndicator(),
],
),
],
),
);

Behaviour without RepaintBoundary

  1. Widget Redrawing:

— Whenever the state of the widget (e.g., isLoading) changes, Flutter has to repaint the entire widget tree.. Even if only one widget CircularProgressIndicatorchanges, the lack of a RepaintBoundary means all widgets in the tree are redrawn unnecessarily.

2. Performance Impact:

— Repainting 50 cards is computationally expensive. This can result in:

  • Frame drops.
  • Noticeable lag, especially on devices with less processing power.

Now, lets Isolate the loader (CircularProgressIndicator) with a RepaintBoundary:

if (isLoading)
RepaintBoundary(
child: CircularProgressIndicator(),// Isolated animation
),

Behaviour with RepaintBoundary

  1. Widget Isolation:

— By wrapping each CircularProgressIndicator inside a RepaintBoundary, Flutter isolates the widget's repainting scope. This means:

  • Only the part of the widget tree inside the RepaintBoundary is repainted.
  • Other parts of the widget tree, such as cards that haven’t changed, remain untouched.

2. Performance Improvement:

— With RepaintBoundary, Flutter optimizes rendering by caching the static parts of the UI and reusing them instead of redrawing everything. This leads to:

  • Smoother animations.
  • Reduced computational overhead.
  • Better frame rates and user experience.

Repaint Boundary Metrics

The metrics provided by the render object linked to a RepaintBoundary helps to evaluate its efficiency and determine whether the boundary optimizes performance effectively

Can we use RepaintBoundary everywhere?

While RepaintBoundary can improve performance by caching its contents, overuse increases memory consumption without guaranteed benefits. Excessive boundaries may unnecessarily bloat memory usage without noticeably improving rendering efficiency. Use them selectively in areas with frequent updates or high repaint costs for optimal results.

As per flutter docs :- “Checking for non-cached images”

Caching an image with RepaintBoundary is good, when it makes sense.

One of the most expensive operations, from a resource perspective, is rendering a texture using an image file. First, the compressed image is fetched from persistent storage. The image is decompressed into host memory (GPU memory), and transferred to device memory (RAM).

In other words, image I/O can be expensive. The cache provides snapshots of complex hierarchies so they are easier to render in subsequent frames. Because raster cache entries are expensive to construct and take up loads of GPU memory, cache images only where absolutely necessary.

How widgets are rendered as UI?

To understand how widgets are rendered as a UI, you can refer to the Flutter documentation on Flutter’s rendering model.

We’ll dive deeper into this topic in a future article!

Summary

  • Use RepaintBoundary strategically to isolate widgets with frequent updates or animations from the rest of the UI!
  • RepaintBoundary ensures that the animation's effect is localized, improving performance and keeping the UI responsive

References

--

--

Prashant Gupta
Prashant Gupta

Written by Prashant Gupta

Passionate and experienced Flutter Developer, specializing in building scalable and robust mobile applications.

Responses (3)

Write a response