De nombreuses applications doivent pouvoir contrôler avec précision ce qui apparaît à l'écran, que ce soit simplement pour aligner un cadre ou un cercle, ou pour minutieusement agencer toute une série d'éléments graphiques aux styles variés.
Dessin de base avec modificateurs et DrawScope
La méthode principale pour dessiner des éléments personnalisés dans Compose consiste à utiliser des modificateurs tels que Modifier.drawWithContent
, Modifier.drawBehind
et Modifier.drawWithCache
.
Par exemple, pour dessiner un objet derrière un composable, vous pouvez utiliser le modificateur drawBehind
pour commencer à exécuter des commandes de dessin :
Spacer( modifier = Modifier .fillMaxSize() .drawBehind { // this = DrawScope } )
Si vous n'avez besoin que d'un composable qui dessine, vous pouvez utiliser Canvas
. Le composable Canvas
est un wrapper pratique pour Modifier.drawBehind
. Vous positionnez le Canvas
dans votre mise en page de la même manière que n'importe quel autre élément d'interface utilisateur avec Compose. Dans le Canvas
, vous pouvez dessiner des éléments avec un contrôle précis sur leur style et leur emplacement.
Tous les modificateurs de dessin exposent un DrawScope
, un environnement de dessin cloisonné qui gère son propre état. Cela vous permet de définir les paramètres d'un groupe d'éléments graphiques. DrawScope
fournit plusieurs champs utiles, tels que size
, un objet Size
spécifiant les dimensions actuelles de DrawScope
.
Pour dessiner un objet, vous pouvez utiliser l'une des nombreuses fonctions de dessin sur DrawScope
. Par exemple, le code suivant dessine un rectangle dans l'angle supérieur gauche de l'écran :
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F drawRect( color = Color.Magenta, size = canvasQuadrantSize ) }
Pour en savoir plus sur les différents modificateurs de dessin, consultez la documentation sur les modificateurs graphiques.
Système de coordonnées
Pour dessiner un élément à l'écran, vous devez connaître son décalage (x
et y
) et sa taille. Avec de nombreuses méthodes de dessin sur DrawScope
, la position et la taille sont fournies par les valeurs de paramètres par défaut. Les paramètres par défaut placent généralement l'élément sur le point [0, 0]
du canevas et indiquent une taille (size
) par défaut qui remplit toute la zone de dessin, comme dans l'exemple ci-dessus. Le rectangle est positionné en haut à gauche. Pour ajuster la taille et la position de votre élément, vous devez comprendre le système de coordonnées de Compose.
L'origine du système de coordonnées ([0,0]
) se trouve tout en haut à gauche de la zone de dessin. x
augmente à mesure qu'il se déplace vers la droite, et y
augmente à mesure qu'il descend.
Par exemple, si vous souhaitez dessiner une ligne diagonale entre l'angle supérieur droit de la zone de canevas et l'angle inférieur gauche, vous pouvez utiliser la fonction DrawScope.drawLine()
et spécifier un décalage de début et de fin avec les positions x et y correspondantes :
Canvas(modifier = Modifier.fillMaxSize()) { val canvasWidth = size.width val canvasHeight = size.height drawLine( start = Offset(x = canvasWidth, y = 0f), end = Offset(x = 0f, y = canvasHeight), color = Color.Blue ) }
Transformations de base
DrawScope
propose des transformations pour modifier la façon dont les commandes de dessin sont exécutées, ou à quel emplacement.
Mise à l'échelle
Utilisez DrawScope.scale()
pour augmenter d'un facteur la taille de vos opérations de dessin. Les opérations telles que scale()
s'appliquent à toutes les opérations de dessin dans le lambda correspondant. Par exemple, le code suivant multiplie scaleX
par 10 et scaleY
par 15 :
Canvas(modifier = Modifier.fillMaxSize()) { scale(scaleX = 10f, scaleY = 15f) { drawCircle(Color.Blue, radius = 20.dp.toPx()) } }
Translation
Utilisez DrawScope.translate()
pour déplacer vos opérations de dessin vers le haut, le bas, la gauche ou la droite. Par exemple, le code suivant déplace le dessin de 100 pixels vers la droite et de 300 pixels vers le haut :
Canvas(modifier = Modifier.fillMaxSize()) { translate(left = 100f, top = -300f) { drawCircle(Color.Blue, radius = 200.dp.toPx()) } }
Rotation
Utilisez DrawScope.rotate()
pour faire pivoter vos opérations de dessin autour d'un point pivot. Par exemple, le code suivant fait pivoter un rectangle à 45 degrés :
Canvas(modifier = Modifier.fillMaxSize()) { rotate(degrees = 45F) { drawRect( color = Color.Gray, topLeft = Offset(x = size.width / 3F, y = size.height / 3F), size = size / 3F ) } }
Encart
Utilisez DrawScope.inset()
pour ajuster les paramètres par défaut du DrawScope
actuel afin de modifier les limites de tracé et de translater les éléments graphiques en conséquence :
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F inset(horizontal = 50f, vertical = 30f) { drawRect(color = Color.Green, size = canvasQuadrantSize) } }
Ce code ajoute une marge intérieure aux commandes de dessin :
Plusieurs transformations
Pour appliquer plusieurs transformations à vos dessins, utilisez la fonction DrawScope.withTransform()
, qui crée et applique une seule transformation combinant toutes les modifications souhaitées. Il est plus efficace d'utiliser withTransform()
que de passer des appels imbriqués pour des transformations individuelles, car toutes les transformations sont effectuées ensemble en une seule opération, ce qui évite à Compose de devoir calculer et enregistrer chaque étape imbriquée.
Par exemple, le code suivant applique une translation et une rotation au rectangle :
Canvas(modifier = Modifier.fillMaxSize()) { withTransform({ translate(left = size.width / 5F) rotate(degrees = 45F) }) { drawRect( color = Color.Gray, topLeft = Offset(x = size.width / 3F, y = size.height / 3F), size = size / 3F ) } }
Opérations de dessin courantes
Dessiner du texte
Pour dessiner du texte dans Compose, vous pouvez généralement utiliser le composable Text
. Toutefois, si vous êtes dans un DrawScope
ou si vous souhaitez dessiner le texte manuellement avec la personnalisation, vous pouvez opter pour la méthode DrawScope.drawText()
.
Pour dessiner du texte, créez un TextMeasurer
à l'aide de rememberTextMeasurer
et appelez drawText
avec l'outil de mesure :
val textMeasurer = rememberTextMeasurer() Canvas(modifier = Modifier.fillMaxSize()) { drawText(textMeasurer, "Hello") }
Mesurer le texte
Le dessin de texte fonctionne légèrement différemment des autres commandes de dessin. Normalement, vous devez indiquer à la commande de dessin la taille (largeur et hauteur) requise pour dessiner la forme ou l'image. Avec le texte, plusieurs paramètres contrôlent la taille du texte affiché, tels que la taille de la police, la police elle-même, les ligatures et l'espacement entre les lettres.
Avec Compose, vous pouvez utiliser un TextMeasurer
pour accéder à la taille de texte mesurée, en fonction des facteurs ci-dessus. Si vous souhaitez dessiner un arrière-plan derrière le texte, vous pouvez utiliser les informations mesurées pour obtenir la taille de la zone occupée par le texte :
val textMeasurer = rememberTextMeasurer() Spacer( modifier = Modifier .drawWithCache { val measuredText = textMeasurer.measure( AnnotatedString(longTextSample), constraints = Constraints.fixedWidth((size.width * 2f / 3f).toInt()), style = TextStyle(fontSize = 18.sp) ) onDrawBehind { drawRect(pinkColor, size = measuredText.size.toSize()) drawText(measuredText) } } .fillMaxSize() )
Cet extrait de code crée un arrière-plan rose pour le texte :
Si vous ajustez les contraintes, la taille de la police ou toute autre propriété qui affecte la taille mesurée, une nouvelle taille est signalée. Vous pouvez définir une taille fixe pour width
et height
. Le texte suit alors le TextOverflow
spécifié. Par exemple, le code suivant affiche le texte dans un tiers de la hauteur et dans un tiers de la largeur de la zone du composable, et définit TextOverflow
sur TextOverflow.Ellipsis
:
val textMeasurer = rememberTextMeasurer() Spacer( modifier = Modifier .drawWithCache { val measuredText = textMeasurer.measure( AnnotatedString(longTextSample), constraints = Constraints.fixed( width = (size.width / 3f).toInt(), height = (size.height / 3f).toInt() ), overflow = TextOverflow.Ellipsis, style = TextStyle(fontSize = 18.sp) ) onDrawBehind { drawRect(pinkColor, size = measuredText.size.toSize()) drawText(measuredText) } } .fillMaxSize() )
Le texte est maintenant dessiné dans les limites spécifiées, avec des points de suspension à la fin :
Dessiner une image
Pour dessiner un ImageBitmap
avec DrawScope
, chargez l'image à l'aide d'ImageBitmap.imageResource()
, puis appelez drawImage
:
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog) Canvas(modifier = Modifier.fillMaxSize(), onDraw = { drawImage(dogImage) })
Dessiner des formes de base
De nombreuses fonctions permettent de dessiner des formes sur DrawScope
. Pour dessiner une forme, utilisez l'une des fonctions de dessin prédéfinies, telles que drawCircle
:
val purpleColor = Color(0xFFBA68C8) Canvas( modifier = Modifier .fillMaxSize() .padding(16.dp), onDraw = { drawCircle(purpleColor) } )
API |
Sortie |
Dessiner un tracé
Un tracé est une série d'instructions mathématiques qui permettent de générer un dessin une fois qu'elles sont exécutées. DrawScope
peut dessiner un tracé à l'aide de la méthode DrawScope.drawPath()
.
Imaginons que vous souhaitiez dessiner un triangle. Vous pouvez générer un tracé avec des fonctions telles que lineTo()
et moveTo()
en utilisant la taille de la zone de dessin.
Appelez ensuite drawPath()
avec ce tracé nouvellement créé pour obtenir un triangle.
Spacer( modifier = Modifier .drawWithCache { val path = Path() path.moveTo(0f, 0f) path.lineTo(size.width / 2f, size.height / 2f) path.lineTo(size.width, 0f) path.close() onDrawBehind { drawPath(path, Color.Magenta, style = Stroke(width = 10f)) } } .fillMaxSize() )
Accéder à l'objet Canvas
Avec DrawScope
, vous n'avez pas d'accès direct à un objet Canvas
. Vous pouvez utiliser DrawScope.drawIntoCanvas()
pour accéder à l'objet Canvas
lui-même au niveau duquel vous pouvez appeler des fonctions.
Par exemple, si vous disposez d'un Drawable
personnalisé que vous souhaitez dessiner sur le canevas, vous pouvez accéder au canevas et appeler Drawable#draw()
, en transmettant l'objet Canvas
:
val drawable = ShapeDrawable(OvalShape()) Spacer( modifier = Modifier .drawWithContent { drawIntoCanvas { canvas -> drawable.setBounds(0, 0, size.width.toInt(), size.height.toInt()) drawable.draw(canvas.nativeCanvas) } } .fillMaxSize() )
En savoir plus
Pour en savoir plus sur le dessin dans Compose, consultez les ressources suivantes :
- Modificateurs graphiques : découvrez les différents types de modificateurs de dessin.
- Pinceau : découvrez comment personnaliser les couleurs de votre contenu.
- Graphiques et mises en page personnalisés dans Compose : Sommet des développeurs Android 2022 : découvrez comment créer une interface utilisateur personnalisée dans Compose avec des mises en page et des graphiques.
- Exemple JetLagged : exemple de composition qui montre comment dessiner un graphique personnalisé.
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé.
- Modificateurs graphiques
- Éléments graphiques dans Compose
- Lignes d'alignement dans Jetpack Compose