onDraw() — qu’est-ce que c’est, mécanisme d’appel et redéfinition de la méthode

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

onDraw() est une méthode clé de la classe View dans le SDK Android responsable du dessin du contenu d’une vue. Le système appelle onDraw à chaque mise à jour de l’apparence de la View — lors du rendu initial, après invalidate() ou lors d’un changement de dimensions. Selon la documentation Android Developers (2026), la redéfinition d’onDraw avec l’API Canvas est le moyen principal de créer des graphiques personnalisés dans les applications Android.

Points essentiels

  • onDraw(Canvas) — une méthode de View appelée par le système pour dessiner le contenu sur le Canvas
  • invalidate() — une demande de redessin de la View, conduisant à l’appel d’onDraw dans le cycle d’image suivant
  • Canvas API fournit les méthodes drawCircle, drawBitmap, drawText, drawPath et autres pour le dessin
  • Le système Android effectue le dessin dans le thread UI, donc onDraw doit être léger et rapide
  • Hardware acceleration accélère automatiquement le dessin via le GPU, depuis Android 3.0 (API 11)

Qu’est-ce qu’onDraw() ?

onDraw(Canvas canvas) est une méthode protected de la classe android.view.View, que le système Android appelle lorsqu’une View doit être dessinée. Le développeur redéfinit cette méthode pour implémenter un dessin personnalisé : formes, texte, images, dégradés, animations. Le paramètre Canvas est une surface graphique sur laquelle toutes les opérations de dessin sont exécutées.

La signature de la méthode est simple : override fun onDraw(canvas: Canvas). À l’intérieur de cette méthode, il ne faut pas créer de nouveaux objets (pour éviter la charge du GC), effectuer des opérations longues ou travailler avec le réseau. View inclut également la méthode onDraw dans son cycle de vie entre onLayout (calcul des positions) et dispatchDraw (dessin des éléments enfants).

En héritant de View, la redéfinition d’onDraw est obligatoire pour afficher un contenu — sinon la View sera vide. En héritant de sous-classes existantes (TextView, ImageView, Button), la redéfinition d’onDraw est optionnelle et sert à ajouter des graphiques supplémentaires par-dessus le contenu standard.

Cycle de dessin de la View

Android effectue le dessin de la View dans une séquence strictement définie appelée depuis le thread principal (UI thread). Le cycle complet se compose de trois phases : measure (mesure des dimensions), layout (calcul des positions) et draw (rendu). onDraw fait partie de la phase draw et est appelé après que les dimensions et la position de la View ont été déterminées.

Phase draw : dispatchDraw et onDraw

draw(Canvas canvas) est une méthode publique de View qui appelle onDraw et dispatchDraw. La méthode draw n’est pas conçue pour être redéfinie — c’est onDraw qui est redéfini. Après l’exécution d’onDraw pour la View actuelle, dispatchDraw est appelé, ce qui invoque récursivement draw pour toutes les Views enfants (si la View actuelle est un conteneur ViewGroup).

Quand le système appelle onDraw

onDraw est appelé dans les conditions suivantes : 1) la View devient visible pour la première fois (après setVisibility(VISIBLE)) ; 2) l’application appelle invalidate() sur cette View ou son parent ; 3) la taille de la View change (nouveau layout) ; 4) une animation associée à la View change (via ValueAnimator ou ObjectAnimator) ; 5) l’état de la View change (pressed, focused, enabled).

Accélération matérielle

Depuis Android 3.0 (API 11), la plupart des opérations Canvas sont accélérées par le matériel via le GPU. Le développeur peut vérifier si l’accélération est activée via canvas.isHardwareAccelerated(). Avec l’accélération matérielle, certaines opérations Canvas ne sont pas prises en charge (par exemple, clipPath avec une région non rectangulaire) et peuvent être ignorées ou provoquer des erreurs.

Canvas API pour les graphiques personnalisés

Canvas fournit un riche ensemble de méthodes de dessin. Toutes les méthodes fonctionnent dans le système de coordonnées actuel, qui peut être modifié par des transformations (translate, rotate, scale, skew). Chaque méthode accepte un objet Paint qui définit la couleur, le style, l’épaisseur de trait, les effets et l’anticrénelage.

Méthode CanvasObjectifParamètres clés de Paint
drawCircleDessiner un cerclecenterX, centerY, radius, paint
drawRectDessiner un rectangleleft, top, right, bottom, paint
drawLineDessiner une lignestartX, startY, endX, endY, paint
drawPathDessiner un chemin arbitrairepath, paint
drawBitmapDessiner une image bitmapbitmap, srcRect, dstRect, paint
drawTextDessiner du textetext, x, y, paint
drawArcDessiner un arc ou un secteurovalRect, startAngle, sweepAngle, useCenter, paint
drawOvalDessiner un ovaleovalRect, paint

L’objet Paint

Paint définit le style de dessin : couleur (setColor), épaisseur de trait (setStrokeWidth), style de remplissage (setStyle — FILL, STROKE, FILL_AND_STROKE), anticrénelage (setAntiAlias), effets (setShadowLayer, setMaskFilter) et dégradés (setShader). Il est recommandé de créer et configurer Paint une fois dans le constructeur de la View, pas dans onDraw, pour éviter la création d’objets dans la boucle de dessin.

Coordonnées et transformations

Canvas utilise un système de coordonnées où l’axe X pointe vers la droite et l’axe Y vers le bas. L’origine (0, 0) est le coin supérieur gauche de la View. Avant d’appeler les méthodes de dessin, le développeur peut modifier le système de coordonnées via canvas.translate(dx, dy), canvas.rotate(degrees, px, py), canvas.scale(sx, sy, px, py). Toutes les opérations de dessin ultérieures seront effectuées dans le système transformé.

Performances d’onDraw

onDraw s’exécute sur le thread UI principal, et sa durée affecte directement le taux d’images (fps). Pour maintenir 60 fps, la méthode onDraw doit se terminer en moins de 16 millisecondes. Tout ralentissement entraîne des chutes d’images (jank), qui se manifestent visuellement par un bégaiement de l’animation ou un retard de défilement.

Règles de performance pour onDraw

Règles principales pour l’optimisation d’onDraw : 1) ne pas créer d’objets dans onDraw — tous les objets Paint, Path, Rect doivent être des champs de classe ; 2) ne pas allouer de mémoire (new) — cela déclenche le ramasse-miettes (GC) et des chutes d’images ; 3) mettre en cache les opérations complexes dans un Bitmap via Bitmap.createBitmap et dessiner le Bitmap préparé ; 4) ne pas effectuer d’opérations d’E/S ou de chargement de ressources.

Utilisation de clipRect pour l’optimisation

clipRect limite la zone de dessin à un rectangle spécifié. Il empêche Canvas de perdre du temps à dessiner des pixels en dehors de la zone visible. Particulièrement efficace lors du défilement de grandes listes ou du zoom : définissez clipRect sur la zone visible (dirty rect), et Canvas ne dessinera que ce qui est visible.

Layer — sauvegarde et restauration

canvas.save() sauvegarde l’état actuel du Canvas (transformation et clip) sur une pile. canvas.restore() restaure le dernier état sauvegardé. Nécessaire pour les transformations temporaires : sauvegardez l’état, appliquez translate/rotate, dessinez, puis restaurez. save et restore sont légers et n’affectent pas les performances s’ils sont utilisés raisonnablement (moins de 10–15 niveaux d’imbrication).

invalidate et postInvalidate

invalidate() est une méthode de View qui informe le système que le contenu de la View est obsolète et doit être redessiné. L’appel à invalidate initie un nouveau cycle de draw dans lequel onDraw sera appelé. invalidate ne doit être appelé que depuis le thread UI (thread principal). Pour l’appel depuis un thread d’arrière-plan, utilisez postInvalidate.

postInvalidate() est une version thread-safe d’invalidate qui envoie une demande de redessin à la file d’attente du thread principal via Handler. Utilisée dans les tâches d’arrière-plan lorsque la View doit être mise à jour après le chargement de données ou des calculs. Peut être combinée avec runOnUiThread pour la synchronisation avec l’UI.

Pour un redessin partiel, utilisez invalidate(Rect dirty) ou invalidate(int l, int t, int r, int b). Cela indique au système que seule la zone spécifiée a changé, pas la View entière. Android optimise le dessin en ne redessinant que le dirty rect, ce qui améliore considérablement les performances des animations avec des mises à jour partielles.

Exemples de code en Kotlin

Voyons des exemples pratiques de redéfinition d’onDraw pour créer des Views personnalisées dans Android avec Kotlin.

View personnalisée — Progression circulaire

Cet exemple crée un indicateur de progression circulaire avec remplissage animé. onDraw dessine deux cercles : un cercle de fond gris et un cercle de remplissage coloré dont l’arc est déterminé par la progression actuelle. L’appel à invalidate dans setProgress garantit le redessin lorsque la valeur change.

kotlin
class CircularProgressView
    @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null
) : View(context, attrs) {

    private val bgPaint = Paint().apply {
        style = Paint.Style.STROKE
        strokeWidth = 12f
        color = Color.parseColor("#E0E0E0")
        isAntiAlias = true
    }

    private val progressPaint = Paint().apply {
        style = Paint.Style.STROKE
        strokeWidth = 12f
        color = Color.BLUE
        isAntiAlias = true
        strokeCap = Paint.Cap.ROUND
    }

    var progress: Float = 0f
        set(value) {
            field = value.coerceIn(0f, 1f)
            invalidate()
        }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val size = minOf(width, height) - 24f
        val oval = RectF(12f, 12f,
                          12f + size, 12f + size)

        canvas.drawArc(oval, 270f, 360f, false, bgPaint)
        canvas.drawArc(oval, 270f,
                        progress * 360f,
                        false, progressPaint)
    }
}

View personnalisée — Fond dégradé avec texte

Cet exemple dessine un rectangle avec un dégradé et du texte par-dessus. Le dégradé est créé via LinearGradient (Shader), et le texte via drawText. Les deux objets Paint sont créés une fois dans le constructeur, tandis qu’onDraw ne fait que mettre à jour la taille du rectangle en fonction de la largeur actuelle de la View.

kotlin
class GradientTextView(context: Context)
    : View(context) {

    private val shaderPaint = Paint().apply {
        isAntiAlias = true
    }

    private val textPaint = Paint().apply {
        color = Color.WHITE
        textSize = 48f
        isAntiAlias = true
        textAlign = Paint.Align.CENTER
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        val gradient = LinearGradient(
            0f, 0f, width.toFloat(), 0f,
            Color.parseColor("#FF6B35"),
            Color.parseColor("#FF0040"),
            Shader.TileMode.CLAMP
        )
        shaderPaint.shader = gradient
        canvas.drawRect(0f, 0f,
                        width.toFloat(),
                        height.toFloat(), shaderPaint)

        val xCenter = width / 2f
        val yCenter = height / 2f
        val yOffset = (textPaint.descent() +
                        textPaint.ascent()) / 2f

        canvas.drawText("Hello from Canvas",
                      xCenter, yCenter - yOffset,
                      textPaint)
    }
}

Horloge animée utilisant invalidate

Cet exemple crée une horloge animée qui met à jour le dessin toutes les 1000 millisecondes. postDelayed dans onDraw appelle invalidate après une seconde, créant une boucle de redessin infinie. Les aiguilles de l’horloge sont dessinées via drawLine avec différentes longueurs et épaisseurs.

kotlin
class AnalogClockView(context: Context)
    : View(context) {

    private val handPaint = Paint().apply {
        style = Paint.Style.STROKE
        isAntiAlias = true
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val cx = width / 2f
        val cy = height / 2f
        val radius = minOf(cx, cy) - 20f

        val now = Calendar.getInstance()
        val hours = now.get(Calendar.HOUR) % 12
        val minutes = now.get(Calendar.MINUTE)
        val seconds = now.get(Calendar.SECOND)

        val secondAngle = Math.toRadians(
            seconds * 6f - 90f)
        handPaint.strokeWidth = 2f
        handPaint.color = Color.RED
        canvas.drawLine(cx, cy,
            cx + cos(secondAngle) * radius * 0.8f,
            cy + sin(secondAngle) * radius * 0.8f,
            handPaint)

        postDelayed({ invalidate() }, 1000)
    }
}

Questions fréquentes

Peut-on appeler onDraw directement ?

Non, il ne faut pas appeler onDraw directement. Pour demander un redessin, utilisez invalidate() (depuis le thread UI) ou postInvalidate() (depuis un thread d’arrière-plan). Le système décidera quand appeler onDraw et optimisera le dessin en fusionnant plusieurs appels invalidate en un seul passage.

Pourquoi onDraw n’est-il pas appelé après invalidate ?

Raisons : la View est cachée (setVisibility(GONE) ou INVISIBLE) ; la View n’a pas été ajoutée à la hiérarchie de la Window ; la taille de la View est 0 (largeur ou hauteur = 0) ; setWillNotDraw(true) est appelé (true par défaut pour ViewGroup). Vérifiez chacun de ces points lors du débogage.

À quelle fréquence onDraw peut-il être appelé ?

À 60 fps, onDraw peut être appelé jusqu’à 60 fois par seconde. À 120 fps (sur les appareils avec écrans 120 Hz) — jusqu’à 120 fois. Chaque appel doit se terminer en environ 8–16 millisecondes. Pendant les animations actives via ObjectAnimator ou ValueAnimator, la fréquence est déterminée par le nombre d’images de l’animation.

Quelle est la différence entre onDraw et dispatchDraw ?

onDraw est responsable du dessin du contenu de la View elle-même. dispatchDraw est responsable du dessin des Views enfants (dans ViewGroup). dispatchDraw est appelé après onDraw et parcourt récursivement tous les éléments enfants. Pour une View ordinaire (pas ViewGroup), dispatchDraw est vide.

Peut-on utiliser Canvas en dehors d’onDraw ?

Oui, on peut créer un Canvas pour un Bitmap via Canvas(bitmap) et dessiner dessus dans n’importe quel thread. Cela permet de pré-rendre des graphiques complexes en arrière-plan. Cependant, le Canvas passé à onDraw appartient au système et ne peut être utilisé que sur le thread UI dans la méthode onDraw.

Résumé

  • onDraw(Canvas) — une méthode clé de View pour le dessin personnalisé avec Canvas API dans Android
  • Cycle de dessin comprend les phases measure, layout et draw — onDraw est appelé dans la phase draw
  • Canvas API inclut les méthodes drawCircle, drawRect, drawPath, drawBitmap, drawText et autres
  • invalidate() demande un redessin depuis le thread UI, postInvalidate() depuis un thread d’arrière-plan
  • Redessin partiel via invalidate(Rect) optimise le rendu en mettant à jour uniquement la zone sale
  • Performances d’onDraw sont critiques : créer des objets dans la méthode provoque GC et chutes d’images
  • Accélération matérielle (depuis API 11) accélère automatiquement les opérations Canvas via le GPU

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