What is CustomPainter and when would you use it?

Low PriorityAsked in ~40% of Flutter interviews

3 min read

Widgets & UI

A CustomPainter has two jobs:

MethodWhat it doesDon't forget
paint(canvas, size)Issue draw commands (drawCircle, drawPath, drawRect, drawText…)Use the given size, not constants
shouldRepaint(old)Tell Flutter whether the painter actually changedReturn false when nothing relevant changed — saves a paint pass

CustomPaint hosts it: CustomPaint(size: ..., painter: ..., foregroundPainter: ..., child: ...). The child still renders normally; the painter draws behind (painter) or on top (foregroundPainter).


Code in action — circular progress

class CircleProgress extends CustomPainter {
  CircleProgress({required this.progress, required this.color});

  final double progress;   // 0.0 → 1.0
  final Color color;

  @override
  void paint(Canvas canvas, Size size) {
    final centre = size.center(Offset.zero);
    final radius = size.shortestSide / 2;

    // Track
    canvas.drawCircle(
      centre,
      radius,
      Paint()
        ..color = Colors.grey.shade300
        ..style = PaintingStyle.stroke
        ..strokeWidth = 10,
    );

    // Progress arc
    canvas.drawArc(
      Rect.fromCircle(center: centre, radius: radius),
      -pi / 2,                  // start at top
      2 * pi * progress,        // sweep angle
      false,
      Paint()
        ..color = color
        ..style = PaintingStyle.stroke
        ..strokeWidth = 10
        ..strokeCap = StrokeCap.round,
    );
  }

  @override
  bool shouldRepaint(CircleProgress old) =>
      progress != old.progress || color != old.color;
}

// Use it
CustomPaint(
  size: const Size.square(120),
  painter: CircleProgress(progress: 0.7, color: Colors.indigo),
);

When to reach for CustomPainter

SituationUse
Charts, graphs, sparklinesCustomPainter
Custom progress / loading indicators
Free-form drawing / signature pads
Geometry that can't be expressed with widgets (arcs, wedges, custom shapes)
Decorative line behind a row of items
A button / common shape you could compose from widgets❌ Just use widgets
Heavy animated visuals✅ but wrap in RepaintBoundary

Common mistakes to avoid

// ❌ shouldRepaint(old) => true — paints every frame
@override
bool shouldRepaint(_) => true;
// ✅ Compare actual inputs

// ❌ shouldRepaint(_) => false — but you changed inputs
// painter never re-renders; users see stale UI

// ❌ Allocating Paint objects in paint()
final p = Paint();    // every frame allocates — GC pressure
// ✅ Reuse Paint where possible, or build them in the constructor

// ❌ Hard-coding sizes
canvas.drawCircle(const Offset(50, 50), 30, paint);
// ✅ Use the size parameter: size.center(Offset.zero), size.shortestSide / 2

// ❌ Not wrapping in RepaintBoundary for animations
// Every frame repaints the painter AND its ancestors. Add a RepaintBoundary.

// ❌ Drawing text without a TextPainter
// canvas.drawText doesn't exist — use TextPainter to lay out then paint

Interview follow-ups

  1. What does shouldRepaint do, and what happens if you return the wrong answer? Flutter calls it on rebuild to decide whether to invoke paint again. Return true always = wasted CPU every frame. Return false when inputs did change = stale visuals. Compare every field that affects the drawing.

  2. Why wrap heavy CustomPaints in a RepaintBoundary? Without it, any repaint inside the painter dirties the parent layer too. A RepaintBoundary gives the painter its own layer, so repainting it doesn't force the ancestors to repaint.

  3. How do you draw text inside a CustomPainter? With TextPainter: TextPainter(text: ..., textDirection: ...)..layout(); painter.paint(canvas, offset). The Canvas doesn't have a direct drawText.

  4. Is CustomPainter slower than using regular widgets? Not inherently — it's actually a lower-level path. The risk is misusing it (always repainting, allocating Paints every frame, lots of overdraw). A correct painter is usually faster than a deeply nested widget tree achieving the same visual.


How helpful was this content?

Please sign in to rate this article.