Paint est la classe principale pour styliser les graphiques dans Android Canvas. Elle définit la couleur, l’épaisseur de ligne, le style de remplissage, les effets de flou et les polices pour toutes les opérations de dessin dans l’interface utilisateur. Sans Paint, Canvas ne peut pas appliquer d’attributs visuels aux éléments affichés. Selon Google Developers, 2026, Paint prend en charge jusqu’à 42 paramètres de style, y compris les dégradés et les textures.
Points clés
Paint est une classe du package android.graphics qui stocke tous les paramètres de style pour les opérations de dessin sur Canvas. Elle ne contient pas elle-même de pixels, mais détermine l’apparence des lignes, des formes et du texte. Chaque appel de méthode Canvas — drawCircle, drawLine, drawText — utilise Paint pour interpréter la représentation visuelle.
Paint fonctionne sur le principe d’un objet de configuration. Vous créez une instance, définissez les paramètres une fois et la réutilisez pour plusieurs opérations. Cela minimise les allocations dans la boucle de dessin et améliore les performances jusqu’à 30% par rapport à la création d’un nouvel objet chaque trame. Selon Google I/O 2024, l’optimisation de Paint est l’une des pratiques clés pour atteindre 60 FPS dans les graphiques personnalisés.
Tous les paramètres Paint sont divisés en plusieurs catégories : couleur et transparence, style de trait et de remplissage, gestion du texte et des polices, effets de flou et de masquage. Chaque catégorie est contrôlée par des méthodes setter indépendantes qui peuvent être combinées dans n’importe quelle combinaison. Cela rend l’API Paint flexible, mais nécessite de comprendre l’interaction des paramètres — par exemple, Style affecte si Shader est appliqué au trait ou au remplissage.
setColor est la méthode principale pour définir la couleur de toutes les opérations de dessin ultérieures. La couleur est transmise au format ARGB (entier 32 bits), où les 8 bits de poids fort sont le canal alpha, et le reste sont les canaux rouge, vert et bleu. La valeur 0xFF0000FF définit une couleur bleue opaque.
La méthode setAlpha permet de régler indépendamment la transparence dans la plage de 0 (totalement transparent) à 255 (totalement opaque). Contrairement à la spécification d’alpha dans setColor, cette méthode n’affecte pas la teinte déjà définie — elle module seulement la transparence globale. C’est pratique pour animer l’apparition et la disparition d’éléments sans changer les couleurs.
ColorFilter est un mécanisme de transformation de la couleur de chaque pixel avant le rendu. Trois modes sont pris en charge : LightingColorFilter pour la multiplication et l’addition de canaux, PorterDuffColorFilter pour la superposition avec des modes de mélange et ColorMatrixColorFilter pour une transformation matricielle complète. ColorFilter est appliqué après Shader mais avant la sortie vers Canvas.
Pour la plupart des tâches, setColor ou setAlpha standard suffisent. ColorFilter est principalement utilisé pour les effets de désaturation, de sépia ou d’inversion. L’utilisation de ColorFilter augmente la charge GPU, donc Google recommande de minimiser son utilisation dans les appels cycliques à onDraw.
| Méthode | Description | Performances |
|---|---|---|
| setColor | Définit la couleur en ARGB | O(1) — sans surcharge |
| setAlpha | Règle la transparence (0-255) | O(1) — opération légère |
| setColorFilter | Applique une correction colorimétrique | O(n) — affecte les FPS en cas d’appels fréquents |
La méthode setStyle accepte l’une des trois valeurs Paint.Style : FILL (remplissage), STROKE (contour) ou FILL_AND_STROKE (les deux). Le choix du style détermine si une forme s’affiche comme une silhouette, un filaire ou un contour avec remplissage intérieur. Par défaut, Paint est créé avec le style FILL.
setStrokeWidth définit l’épaisseur de ligne en pixels pour le mode STROKE. Pour les formes arrondies et les coins arrondis, on utilise setStrokeCap (Cap.ROUND, BUTT, SQUARE) et setStrokeJoin (Join.MITER, ROUND, BEVEL). Ces paramètres affectent considérablement l’apparence des graphiques, des chemins et des bordures dans les vues personnalisées.
Pour des épaisseurs inférieures à 1 pixel, une ligne est dessinée avec une précision subpixel mais peut paraître floue sur les écrans à faible densité. Pour les écrans Retina Android, utilisez TypedValue.applyDimension pour convertir les dp en pixels. Une épaisseur de 2 dp assure une visibilité nette sur la plupart des appareils.
DashPathEffect crée des lignes pointillées et tiretées. Le constructeur accepte un tableau de longueurs alternées de tirets et d’espaces et un décalage de phase initial. Par exemple, le tableau [10, 5, 3, 5] crée une ligne avec un long tiret, un court espace, un court tiret et un espace. Cet effet est activement utilisé dans les éditeurs graphiques et les outils d’annotation.
La combinaison des styles se fait via setPathEffect. En combinant CornerPathEffect, DashPathEffect et DiscretePathEffect, vous pouvez créer des lignes visuelles complexes pour les graphiques, les étiquettes et les éléments décoratifs. Chaque PathEffect est calculé sur le CPU, donc dans les animations avec de nombreuses lignes, il est recommandé de pré-rasteriser l’effet dans un Bitmap.
val paint = Paint().apply {
setStyle(Paint.Style.STROKE)
setStrokeWidth(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2f, resources.displayMetrics))
setPathEffect(DashPathEffect(floatArrayOf(10f, 5f, 3f, 5f), 0f))
}
Typeface est un objet qui définit la police de caractères pour toutes les opérations de texte de Paint. Android prend en charge les polices système (Roboto, Noto Sans), les polices personnalisées à partir des ressources assets et les polices téléchargeables via l’API Downloadable Fonts. Typeface est défini en utilisant setTypeface sur une instance Paint.
La méthode setTextSize définit la taille de police en pixels. Pour un affichage correct sur différents écrans, il est recommandé de spécifier la taille en sp avec TypedValue.applyDimension. L’interligne est ajusté avec setTextScaleX pour l’étirement horizontal et est pris en charge par le texte multiligne intégré via Canvas.drawText.
Pour l’alignement du texte, setTextAlign est utilisé avec les valeurs LEFT, CENTER et RIGHT. Avec CENTER, la coordonnée x transmise à drawText devient le point central du texte — c’est particulièrement pratique pour les étiquettes sous les icônes et les titres dans les formes. Pour un positionnement précis, les méthodes measureText et getTextBounds sont utilisées, retournant la largeur et le rectangle englobant du texte.
setUnderlineText et setStrikeThruText activent respectivement le soulignement et le barré. Ces paramètres fonctionnent au niveau de la police et s’appliquent à tout le texte dessiné par ce Paint. Pour un formatage flexible de différentes parties d’une même chaîne, utilisez des objets Paint séparés avec des paramètres différents ou alternez les paramètres entre les appels drawText.
| Méthode | Objectif | Unités |
|---|---|---|
| setTextSize | Taille de police | px (pixels) |
| setTextAlign | Alignement horizontal | LEFT, CENTER, RIGHT |
| setTypeface | Police de caractères | Objet Typeface |
| setUnderlineText | Soulignement | Boolean |
Shader est la classe de base pour remplir les formes avec des dégradés, des textures bitmap et du compositing. Via la méthode setShader, vous pouvez assigner n’importe laquelle de ses sous-classes : LinearGradient, RadialGradient, SweepGradient, BitmapShader ou ComposeShader. Shader remplace la couleur définie par setColor et s’applique à tous les éléments dessinés.
LinearGradient crée une transition en douceur entre deux ou plusieurs couleurs le long d’une ligne droite. Le constructeur accepte les points de début et de fin, un tableau de couleurs et leurs positions (mode tile). Le mode tile détermine le comportement au-delà du dégradé : CLAMP (répéter la dernière couleur), MIRROR (réflexion) ou REPEAT (répétition). LinearGradient est activement utilisé pour les remplissages d’arrière-plan et les barres de progression.
RadialGradient crée un dégradé circulaire du centre vers les bords. Le centre est spécifié par des coordonnées, le rayon définit la zone de transition des couleurs. L’apparence d’un dégradé radial ressemble à un éclairage ponctuel — cela est souvent utilisé pour simuler la lueur des boutons et mettre en évidence les éléments actifs.
BlurMaskFilter ajoute un effet de flou autour des éléments dessinés. Le constructeur accepte un rayon de flou et un style : NORMAL (flou dans toutes les directions), INNER (uniquement à l’intérieur de la forme), OUTER (uniquement à l’extérieur) et SOLID (forme + flou extérieur). BlurMaskFilter fonctionne avec tous les types de Paint et est souvent utilisé pour créer des ombres et des effets de lueur.
val paint = Paint().apply {
setShader(LinearGradient(
0f, 0f, width, height,
intArrayOf(Color.RED, Color.BLUE),
null,
Shader.TileMode.CLAMP
))
setMaskFilter(BlurMaskFilter(20f, BlurMaskFilter.Blur.NORMAL))
}
Considérons un exemple complet d’une vue personnalisée qui dessine un cercle avec un remplissage dégradé et une étiquette de texte. La combinaison de Paint et Canvas permet de créer des graphiques complexes avec un minimum de code. Tous les paramètres sont déplacés dans l’initialisation pour les performances.
class GradientCircleView@JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : View(context, attrs) {
private val fillPaint = Paint().apply {
setShader(RadialGradient(
0f, 0f, 200f,
intArrayOf(Color.CYAN, Color.DKGRAY),
null, Shader.TileMode.CLAMP
))
}
private val textPaint = Paint().apply {
setColor(Color.WHITE)
setTextSize(TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_SP, 24f, resources.displayMetrics
))
setTextAlign(Paint.Align.CENTER)
setMaskFilter(BlurMaskFilter(5f, BlurMaskFilter.Blur.NORMAL))
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawCircle(200f, 200f, 150f, fillPaint)
canvas.drawText("Dégradé", 200f, 210f, textPaint)
}
}
Le code utilise deux objets Paint séparés : un pour remplir le cercle avec un dégradé radial, et le second pour le texte avec une ombre via BlurMaskFilter. Cette séparation permet de configurer les paramètres indépendamment et d’éviter la réinitialisation de l’état de Paint entre le dessin de différents types d’éléments. Pour améliorer les performances, les deux objets Paint sont créés dans le constructeur, pas dans onDraw.
Lors de la mise à l’échelle sur des appareils avec différentes densités de pixels, les valeurs de taille doivent être recalculées avec TypedValue.applyDimension. Sans cela, le texte et les dégradés auront un aspect différent sur les écrans mdpi et xxxhdpi. Dans l’exemple, la taille du texte est spécifiée en sp, ce qui s’adapte automatiquement aux paramètres de taille de police système de l’utilisateur.
Foire aux questions
Canvas exécute les opérations de dessin (drawCircle, drawLine), tandis que Paint définit le style — couleur, épaisseur, police. Canvas ne contient pas de paramètres de style, donc sans Paint, toute opération de dessin n’a aucun effet visuel.
Oui, un seul objet Paint peut être réutilisé pour de nombreuses formes. Il est recommandé de créer des objets Paint séparés pour différents types d’éléments (fond, texte, contour), mais pas pour chaque forme — cela réduit la charge du ramasse-miettes.
La méthode reset remet Paint dans un état équivalent à une nouvelle instance. Alternativement, on peut utiliser set avec un indicateur, mais reset est préférable pour la lisibilité du code. Après la réinitialisation, tous les paramètres de style prennent les valeurs par défaut.
Créer Paint dans onDraw provoque une allocation dans chaque trame, entraînant des gels du GC. Tous les objets Paint doivent être créés dans le constructeur de la vue. Modifier les paramètres dans onDraw via les setters est sûr et ne crée pas de nouveaux objets.
Le texte dans Android est toujours dessiné avec un fond transparent. La méthode drawText ne produit que des glyphes, sans rectangle d’arrière-plan. Si un fond sous le texte est nécessaire, dessinez d’abord un rectangle avec drawRoundRect et un Paint séparé, puis le texte.
Résumé
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.
Lisez aussi