Migration to Flutter Guide
Discover our battle-tested 21-step framework for a smooth and successful migration to Flutter!
Home
Glossary

CustomPaint in Flutter

What Is CustomPaint in Flutter?

CustomPaint is a Flutter widget that allows developers to draw custom shapes, visuals, and effects directly on a canvas. It is used when standard widgets are not flexible enough to represent a specific visual requirement.

CustomPaint is commonly applied in advanced UI scenarios such as:

  • Charts
  • Custom indicators
  • Non-standard shapes
  • Highly customized design systems.

Why does CustomPaint matter in Flutter app development?

CustomPaint unlocks full control over rendering. It allows teams to implement visuals that would otherwise require complex widget trees or platform-specific code.

For performance-critical or visually unique components, CustomPaint often results in simpler and more efficient implementations than composing many small widgets.

How does CustomPaint work?

CustomPaint delegates rendering to a CustomPainter class. This class receives a Canvas object and a Size, which together define the drawing surface.

Inside the painter, drawing is performed imperatively using low-level operations such as drawing lines, paths, circles, and shapes. Flutter calls the paint method whenever the widget needs to be redrawn.

The framework also relies on the shouldRepaint method to decide whether a repaint is necessary, which makes CustomPaint efficient when implemented correctly.

Example of CustomPaint in Flutter

A simple example of drawing a circle:

class CirclePainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.blue
      ..style = PaintingStyle.fill;

    canvas.drawCircle(
      size.center(Offset.zero),
      size.width / 2,
      paint,
    );
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}

Usage in a widget:

CustomPaint(
  size: const Size(40, 40),
  painter: CirclePainter(),
)

This pattern scales to much more complex visuals while keeping rendering logic isolated from layout.

CustomPaint in design systems

CustomPaint becomes especially valuable when building highly atomic design systems.

Instead of assembling components from multiple widgets, teams can create low-level visual primitives such as:

  • Custom borders and separators
  • Progress indicators
  • Icons and decorative elements
  • Dynamic backgrounds and overlays

This approach keeps components small, predictable, and easy to theme. It also reduces layout complexity, which is important when design systems aim for consistency across many screens.

The trade-off is higher implementation complexity and the need for strong internal conventions.

When to use CustomPaint?

CustomPaint is useful when an application requires fine-grained control over rendering that standard Flutter widgets cannot provide.

Custom visual rendering

CustomPaint allows developers to draw directly onto a canvas using the paint method of a CustomPainter.

This approach is appropriate when a visual element requires:

  • Custom shapes
  • Gradients
  • Procedural drawing

These cases may be inefficient or impossible to implement with standard Flutter widgets.

Performance-sensitive rendering

CustomPaint can also be useful when performance is a concern.

If widget composition introduces:

  • Unnecessary rebuilds
  • Complex layout calculations

rendering directly on a canvas can reduce overhead and improve frame rates.

This is particularly helpful for reusable visual primitives such as:

  • Graphs
  • Charts
  • Icons

Precise visual fidelity

CustomPaint is well suited for design systems that require precise visual fidelity.

It allows developers to ensure that every pixel, line, or curve matches the intended specification.

This approach fits best in mature codebases that prioritize:

  • Consistency
  • Reusable visual primitives
  • Predictable rendering behavior

Examples include complex dashboards, game UI elements, or custom animated widgets.

When not to use CustomPaint?

CustomPaint is not always the right choice and can introduce unnecessary complexity in some situations.

Standard layouts

If a design can be implemented using existing Flutter widgets such as:

it is usually simpler and more maintainable to use those widgets.

Adding a canvas layer with CustomPaint in these cases increases complexity and can make the code harder to read or debug.

Highly dynamic layouts

CustomPaint is not well suited for layouts that change frequently based on:

  • Screen size
  • Content
  • User interaction

CustomPaint requires developers to manually handle sizing, positioning, and drawing logic. For dynamic interfaces, standard widgets with built-in layout behavior provide a more predictable solution.

Limited experience with canvas rendering

Teams with limited experience in canvas-based rendering should avoid using CustomPaint for routine tasks.

Errors in:

  • Coordinate calculations
  • Painting order
  • State management

can introduce subtle visual bugs and create long-term maintenance challenges. Overusing CustomPaint in simple scenarios may make the codebase more fragile without providing meaningful benefits.

Common mistakes when using CustomPaint

Typical mistakes when using CustomPaint include:

  • Repainting too often due to incorrect shouldRepaint logic.
  • Mixing layout logic with drawing logic.
  • Ignoring device pixel ratio and scaling.
  • Implementing complex interaction logic inside the painter.

CustomPainter should focus purely on rendering, not state or interaction handling.

Best practices for CustomPaint

When working with CustomPaint:

  • Keep painters small and focused.
  • Separate rendering from layout and interaction.
  • Minimize repaints by implementing shouldRepaint correctly.

Learn more

Design system Flutter

Building a Design System in a Large Flutter App

Flutter is known for its seamless UI/UX features and robust design elements. It allowed us to deliver a unique customer experience in the “CA24 Mobile” banking app. This article shares some of the learnings and pain points behind implementing it in this large project.

Advantages of design system

Benefits of a Design System: Why Your Digital Product Needs One

Building a new digital product, such as a web or mobile application, is complex. You need to map user stories - create a simple description of features - then apply them to the developers' scope of work and the app’s design. Discover how a design system can unleash efficiency, consistency, and scalability in your digital product.

Implementing Live Whiteboard With Flutter and Firestore Database

Implementing Live Whiteboard With Flutter and Firestore Database

Whiteboards make it easier to collaborate on designs, teach people new concepts, and express ideas. In this blog post, we explore a possible implementation of a whiteboard using Flutter to create a mobile application and Firestore database as backend.