When would you implement a CustomPainter and how does shouldRepaint work?
Knowledge of Flutter render pipeline repaint optimization.
Use CustomPainter for charts; check fields in shouldRepaint to skip frames; pass Listenable to bypass build layout.
WHAT THIS TESTS: This question probes whether you understand Flutter's rendering pipeline beyond the widget layer. The interviewer wants to know if you can distinguish between widget rebuilds, layout, and paint phases; if you know when imperative drawing beats declarative widgets; and whether you grasp the performance cost of unnecessary GPU work. It also checks if you understand how to integrate with the framework's repaint scheduling via Listenable rather than brute-forcing rebuilds.
A GOOD ANSWER COVERS: First, a concrete scenario where CustomPainter is the right tool, such as drawing a real-time audio waveform, a complex chart with thousands of data points, or a custom gradient mesh that would require an impractical number of nested widgets. Second, the mechanics of shouldRepaint: the framework calls it when a new delegate instance is provided, and you must compare the fields of the old delegate against the new one; return false only when the painting would be visually identical. Third, the performance implication: returning true blindly causes the render object to repaint on every build, which burns GPU time and can drop frames from 60fps to 30fps or lower on budget devices. Fourth, the optimal pattern for animation: extend CustomPainter and supply a repaint Listenable like an AnimationController in the constructor, or make the painter itself a ChangeNotifier; this lets the render object listen directly and skip both the build and layout phases entirely.
COMMON WRONG ANSWERS: A major red flag is saying shouldRepaint always returns true because Flutter is fast enough; this ignores the GPU cost of rasterization and will cause jank. Another is confusing shouldRepaint with setState logic, treating it as a trigger rather than a gate. Candidates also err by suggesting you should create a new CustomPainter instance on every frame inside build; doing so forces shouldRepaint to run constantly and often loses the benefit of the Listenable optimization. Finally, some engineers forget that multiple widgets may share the same Canvas, so using exotic BlendModes without Canvas.saveLayer and restore can accidentally erase previously drawn widgets.
LIKELY FOLLOW-UPS: The interviewer may ask how you would handle hit testing for irregular shapes inside a CustomPainter, which involves implementing hitTest and doing point-in-path math. They might also probe semantics by asking about semanticsBuilder and shouldRebuildSemantics for accessibility. Another common pivot is layer caching: when would you use PictureRecorder or cache a picture to avoid redrawing static content? You should also be ready to discuss when to use CustomPaint versus a RenderBox subclass for even lower-level control.
ONE CONCRETE EXAMPLE: Imagine a weather app that renders a smooth radial gradient sky behind animated clouds. The sky is static, so the Sky painter has no fields and shouldRepaint returns false. The clouds move, so a Cloud painter accepts an animation value and an AnimationController as its repaint argument. In shouldRepaint, the cloud painter compares the old offset value; if it differs, it returns true so the canvas repaints only the cloud layer. Because the sky painter never repaints and the cloud painter uses the Listenable repaint, the app stays at 60fps without rebuilding the widget tree on every animation tick.
Read the original → api.flutter.dev
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.