CustomPainter — ce que c'est, méthodes paint et shouldRepaint dans Flutter

Auteur : IT Sectr Publié le : 2026-07-22 Temps de lecture : 10 min

CustomPainter est une classe abstraite du SDK Flutter qui offre aux développeurs un contrôle total sur le rendu de graphiques 2D personnalisés sur Canvas. Le développeur crée une sous-classe de CustomPainter et implémente deux méthodes obligatoires : paint(Canvas, Size) et shouldRepaint(covariant CustomPainter oldDelegate). Selon la documentation de l'API Flutter (2026), CustomPainter est utilisé conjointement avec le widget CustomPaint, qui délègue le rendu à l'objet CustomPainter fourni à chaque image d'animation ou changement d'état.

Points Clés

  • CustomPainter — classe abstraite de Flutter qui définit le rendu personnalisé sur Canvas via les méthodes paint et shouldRepaint
  • CustomPaint — widget qui accepte CustomPainter comme paramètre painter ou foregroundPainter et affiche le résultat à l'écran
  • Canvas — objet fournissant des méthodes de dessin (drawLine, drawCircle, drawPath, drawRect, drawArc et autres)
  • shouldRepaint — méthode d'optimisation qui détermine si l'objet doit être redessiné lors de la mise à jour
  • size — taille de la zone de dessin passée à paint(Canvas canvas, Size size) depuis le widget parent

Qu'est-ce que CustomPainter ?

CustomPainter est une classe de base de Flutter pour implémenter des graphiques 2D personnalisés. Elle remplace l'approche de surcharge de onDraw dans Android, offrant un modèle de rendu plus flexible et déclaratif. Le développeur crée une sous-classe de CustomPainter, surcharge la méthode paint où il reçoit Canvas et Size, et exécute toutes les opérations de dessin sur Canvas. Le widget CustomPaint gère l'appel à paint et intègre le résultat dans l'arbre de widgets.

La différence clé entre CustomPainter et le dessin direct via Canvas est la séparation de la logique de rendu (paint) et du déclencheur de redessin (shouldRepaint). Le système Flutter appelle shouldRepaint chaque fois que le widget parent change. Si shouldRepaint renvoie false, paint n'est pas appelé, ce qui économise des ressources. Ce mécanisme est similaire à shouldRebuild dans RenderObject et fait partie de l'architecture Flutter avec ses trois arbres (Widget, Element, RenderObject).

CustomPaint est un widget qui accepte les paramètres painter (couche d'arrière-plan) et foregroundPainter (couche de premier plan). Les deux paramètres acceptent des objets CustomPainter. Le painter d'arrière-plan est dessiné avant le widget enfant de CustomPaint, et le foregroundPainter après. Cela permet d'utiliser CustomPaint comme conteneur avec un fond décoratif ou une superposition sans perdre la possibilité d'intégrer des widgets normaux à l'intérieur.

Canvas et Paint dans Flutter

Canvas est l'objet central de dessin dans Flutter, encapsulant la surface graphique. Il fournit environ 40 méthodes de dessin : drawLine, drawCircle, drawRect, drawPath, drawArc, drawImage, drawPicture, drawPoints et autres. Canvas dans Flutter correspond à une classe similaire dans Android Canvas mais est adapté à l'architecture Dart et au Flutter Engine. Canvas fonctionne dans un système de coordonnées où l'origine (0, 0) est le coin supérieur gauche.

Paint — à ne pas confondre avec la méthode paint() — est une classe qui définit le style de dessin : couleur (color), épaisseur de trait (strokeWidth), style (style : fill ou stroke), opacité, mode de mélange (blendMode) et masque d'anticrénelage. Paint est configuré avant le dessin et passé aux méthodes de Canvas. Important : Paint est un objet mutable, mais il est recommandé de le créer une fois et de le réutiliser, en modifiant uniquement les paramètres nécessaires.

Méthode CanvasObjectifParamètres
drawCircleDessine un cercleOffset center, double radius, Paint paint
drawLineDessine un segment de ligneOffset p1, Offset p2, Paint paint
drawRectDessine un rectangleRect rect, Paint paint
drawPathDessine un tracé arbitrairePath path, Paint paint
drawArcDessine un arc ou secteurRect rect, double startAngle, double sweepAngle, bool useCenter, Paint paint
drawRRectRectangle aux coins arrondisRRect rrect, Paint paint
drawOvalDessine un ovaleRect rect, Paint paint
drawImageDessine une image depuis ImageImage image, Offset p, Paint paint

Transformations du Canvas

Canvas prend en charge les transformations du système de coordonnées : translate(double dx, double dy) déplace l'origine ; rotate(double radians) fait pivoter le système ; scale(double sx, double sy) met à l'échelle ; skew(double sx, double sy) incline. Avant une transformation, il est recommandé de sauvegarder l'état du Canvas via save() et de le restaurer après la fin via restore(). Cela empêche l'accumulation de transformations dans les appels paint ultérieurs.

Méthodes paint et shouldRepaint

paint(Canvas canvas, Size size) est la méthode obligatoire qui implémente toute la logique de dessin. Le paramètre canvas est la surface graphique pour le dessin. Le paramètre size est la taille de la zone allouée pour le dessin (largeur et hauteur en pixels logiques). Canvas est préconfiguré de sorte que l'origine (0,0) corresponde au coin supérieur gauche de la zone de dessin. Toutes les coordonnées sont spécifiées par rapport à cette origine.

shouldRepaint(covariant CustomPainter oldDelegate) est une méthode obligatoire qui optimise la fréquence de redessin. Flutter appelle shouldRepaint à chaque mise à jour de l'arbre de widgets qui affecte CustomPainter. Si la méthode renvoie false, l'image déjà rendue est considérée comme valide et paint n'est pas appelé. Une implémentation typique est : return oldDelegate.someField != someField — comparaison des champs de l'ancien et du nouveau painter pour déterminer la nécessité d'un redessin.

Pour les images animées ou en constante évolution (horloges, indicateurs de chargement, graphiques), shouldRepaint doit renvoyer true à chaque changement d'état. Si l'objet est statique (logo, icône, fond), shouldRepaint renvoie false après le premier rendu. Flutter met automatiquement en cache le résultat de paint et ne redessine que lorsque la taille, l'opacité ou l'appel shouldRepaint changent.

Exemple de dessin personnalisé avec CustomPainter en Dart

Créons GaugePainter — un indicateur circulaire personnalisé avec remplissage animé. CustomPainter accepte la valeur actuelle (progression de 0,0 à 1,0) et dessine un arc avec un dégradé. La méthode shouldRepaint compare la valeur de progression pour l'optimisation. CustomPaint est placé dans l'arbre de widgets avec le paramètre size pour limiter la zone de dessin.

dart
class GaugePainter extends CustomPainter {
    final double progress;
    final Color startColor;
    final Color endColor;

    GaugePainter({
        required this.progress,
        this.startColor = Colors.blue,
        this.endColor = Colors.cyan,
    });

    @override
    void paint(Canvas canvas, Size size) {
        final center = Offset(size.width / 2,
            size.height / 2);
        final radius = center.dx - 12;
        final bgPaint = Paint()
            ..color = Colors.grey.withOpacity(0.3)
            ..style = PaintingStyle.stroke
            ..strokeWidth = 16
            ..strokeCap = StrokeCap.round;

        final progressPaint = Paint()
            ..shader = LinearGradient(
                colors: [startColor, endColor],
            ).createShader(
                Rect.fromCircle(
                    center, radius))
            ..style = PaintingStyle.stroke
            ..strokeWidth = 16
            ..strokeCap = StrokeCap.round;

        canvas.drawCircle(center, radius, bgPaint);
        canvas.drawArc(
            Rect.fromCircle(center, radius),
            -math.pi / 2,
            2 * math.pi * progress,
            false, progressPaint);
    }

    @override
    bool shouldRepaint(
        GaugePainter oldDelegate) {
        return oldDelegate.progress != progress;
    }
}

CustomPainter avec Path pour les formes complexes

L'exemple dessine un graphique d'ondes en utilisant Path. Path permet de construire des contours arbitraires à partir de lignes, de courbes de Bézier et d'arcs. Après avoir construit le contour, il est rempli de couleur ou tracé avec une ligne. Dans l'exemple, le graphique est construit à partir d'un tableau de points simulant une forme d'onde.

dart
class WavePainter extends CustomPainter {
    final List<double> values;

    WavePainter({required this.values});

    @override
    void paint(Canvas canvas, Size size) {
        final path = Path();
        final dx = size.width /
            (values.length - 1);

        path.moveTo(0, size.height);
        for (var i = 0; i < values.length; i++) {
            final x = i * dx;
            final y = size.height *
                (1 - values[i]);
            path.lineTo(x, y);
        }
        path.lineTo(size.width, size.height);
        path.close();

        final fillPaint = Paint()
            ..color = Colors.blue.withOpacity(0.3)
            ..style = PaintingStyle.fill;

        canvas.drawPath(path, fillPaint);
    }

    @override
    bool shouldRepaint(
        WavePainter oldDelegate) {
        return oldDelegate.values != values;
    }
}

ForegroundPainter et backgroundPainter : différence

painter (arrière-plan) est dessiné avant le widget enfant de CustomPaint. Si CustomPaint a un widget enfant (paramètre child), le painter d'arrière-plan est affiché en dessous. Cela convient pour les décorations : barres de progression, motifs d'arrière-plan, filigranes. foregroundPainter est dessiné après le widget enfant, c'est-à-dire par-dessus. Il est utilisé pour les superpositions : reflets, masques, règles de mesure, annotations.

La différence entre painter et foregroundPainter est cruciale pour l'ordre Z. Si vous devez dessiner quelque chose derrière le contenu — utilisez painter. Si par-dessus le contenu — foregroundPainter. Dans certains cas, vous pouvez utiliser les deux painters simultanément : arrière-plan via painter, superposition d'étiquette via foregroundPainter. Cela permet de séparer la logique de différentes couches graphiques en deux classes CustomPainter distinctes.

Le paramètre size dans la méthode paint est le même pour les deux painters et est déterminé par la taille de la zone allouée pour CustomPaint. La taille peut être définie explicitement via le paramètre size dans CustomPaint ou implicitement via le conteneur parent. Si la taille est Size.zero, paint n'est pas appelé — Flutter ignore le rendu pour une zone de taille nulle. Ce comportement doit être pris en compte lors de l'animation de l'apparition d'éléments.

Optimisation des performances de CustomPainter

La règle principale des performances de CustomPainter est de ne pas créer d'objets à l'intérieur de la méthode paint. Canvas, Paint, Path, Rect, Offset et autres objets de dessin doivent être créés dans le constructeur de CustomPainter ou mis en cache. Créer des objets dans paint entraîne des allocations à chaque image, ce qui à 60 images par seconde provoque des collectes de déchets fréquentes et des saccades d'animation (jank).

La mise en cache de Path accélère considérablement le rendu des tracés complexes répétés. Si le tracé ne change pas entre les images (par exemple, une grille d'arrière-plan), créez le Path une fois et réutilisez-le plusieurs fois. RepaintBoundary est un widget enveloppant qui empêche le redessin de CustomPainter lorsque l'arbre de widgets supérieur change. Si CustomPainter est statique, enveloppez-le dans un RepaintBoundary pour l'isoler.

Pour les CustomPainter animés avec des redessins fréquents, utilisez Ticker ou AnimationController avec shouldRepaint renvoyant true à chaque changement de la valeur animée. Il est optimal de comparer le champ animé dans shouldRepaint plutôt que de redessiner à chaque image inutilement. Mise en cache de Rect pour les dégradés complexes : si les couleurs du dégradé ne changent pas, vous pouvez mettre en cache le Shader via Paint.shader.

Foire aux questions

Quelle est la différence entre CustomPainter et Canvas dans Flutter ?

CustomPainter est une classe de contrat qui définit quoi et comment dessiner sur Canvas. Canvas est l'objet de dessin lui-même, qui fournit des méthodes (drawCircle, drawLine, etc.). CustomPainter reçoit Canvas via la méthode paint et contrôle son utilisation. Un même Canvas peut être utilisé par différents CustomPainter à différents moments.

Peut-on utiliser CustomPainter sans CustomPaint ?

Non, CustomPainter n'a pas de sens sans CustomPaint. CustomPaint est le widget qui appelle la méthode paint de CustomPainter et affiche le résultat à l'écran. Sans CustomPaint, Canvas ne sera pas créé et paint ne s'exécutera pas. Vous pouvez cependant implémenter votre propre RenderObject avec Canvas, mais c'est une approche de plus bas niveau.

Comment animer un CustomPainter ?

Utilisez un AnimationController avec un Ticker, en passant la valeur animée à CustomPainter via les paramètres du constructeur. Lorsque la valeur change, appelez setState() dans le widget contenant CustomPaint, ce qui déclenche l'appel à shouldRepaint. Si shouldRepaint renvoie true, le système appelle paint pour la nouvelle image d'animation.

Pourquoi CustomPainter ne se met-il pas à jour lorsque les données changent ?

La cause est presque toujours shouldRepaint qui renvoie false. Vérifiez que les champs de oldDelegate sont correctement comparés avec les nouvelles valeurs. Si un objet mutable est utilisé, shouldRepaint peut ne pas détecter les changements car la référence à l'objet reste la même. Utilisez == ou des objets immutables pour une comparaison correcte.

Peut-on utiliser CustomPainter pour l'animation dans ReorderableListView ?

Oui, CustomPainter est utilisé pour rendre des décorations personnalisées dans des listes complexes. Cependant, notez que lors de la réorganisation des éléments, le RepaintBoundary à l'intérieur de ListView met en cache le rendu de chaque élément. CustomPainter doit être léger et ne pas contenir d'opérations lourdes dans paint pour ne pas ralentir l'animation de glissement.

Résumé

  • CustomPainter — classe abstraite de Flutter pour le rendu 2D personnalisé avec les méthodes paint et shouldRepaint
  • CustomPaint — widget qui accepte painter (arrière-plan) et foregroundPainter (premier plan) pour afficher des graphiques
  • Canvas — objet avec des méthodes de dessin : drawLine, drawCircle, drawPath, drawRect, drawArc et autres
  • Paint — classe définissant le style de dessin : couleur, épaisseur, style (fill/stroke), opacité et mode de mélange
  • shouldRepaint — méthode d'optimisation qui renvoie true uniquement lorsque les champs affectant le rendu changent
  • Créer des objets dans paint est interdit — tous les Paint, Path, Rect doivent être mis en cache pour 60 fps
  • RepaintBoundary — widget pour isoler CustomPainter des redessins de l'arbre de widgets supérieur

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi