Dans Compose, un élément Brush
décrit la façon dont un objet est dessiné à l'écran. Il détermine la ou les couleurs qui remplissent la zone de dessin (cercle, carré, ligne droite, etc.). Il existe quelques pinceaux intégrés utiles pour le dessin, tels que LinearGradient
, RadialGradient
ou un pinceau SolidColor
pour les couleurs unies.
Vous pouvez utiliser les pinceaux avec les appels de dessin Modifier.background()
, TextStyle
ou DrawScope
pour appliquer le style de peinture au contenu dessiné.
Par exemple, vous pouvez appliquer un pinceau de dégradé horizontal au dessin d'un cercle dans DrawScope
:
val brush = Brush.horizontalGradient(listOf(Color.Red, Color.Blue)) Canvas( modifier = Modifier.size(200.dp), onDraw = { drawCircle(brush) } )
Pinceaux à dégradé
Divers pinceaux intégrés permettent d'obtenir différents effets de dégradé. Ces pinceaux vous permettent de spécifier la liste des couleurs à partir desquelles vous souhaitez créer le dégradé.
Liste des pinceaux à dégradé disponibles et résultat correspondant :
Type de pinceau à dégradé | Résultat |
---|---|
Brush.horizontalGradient(colorList) |
|
Brush.linearGradient(colorList) |
|
Brush.verticalGradient(colorList) |
|
Brush.sweepGradient(colorList)
Remarque : Pour une transition en douceur entre les couleurs, la dernière couleur doit correspondre à la couleur de départ. |
|
Brush.radialGradient(colorList) |
Modifier la distribution des couleurs avec colorStops
Pour personnaliser la façon dont les couleurs apparaissent dans le dégradé, vous pouvez ajuster la valeur colorStops
pour chacune d'elles. colorStops
doit être une fraction comprise entre 0 et 1. Si cette valeur est supérieure à 1, les couleurs ne s'afficheront pas dans le dégradé.
Vous pouvez configurer les arrêts de couleur pour définir des quantités différentes, par exemple pour utiliser davantage une couleur spécifique, ou dans une moindre mesure :
val colorStops = arrayOf( 0.0f to Color.Yellow, 0.2f to Color.Red, 1f to Color.Blue ) Box( modifier = Modifier .requiredSize(200.dp) .background(Brush.horizontalGradient(colorStops = colorStops)) )
Les couleurs sont dispersées au niveau du décalage fourni comme spécifié dans la paire colorStop
(moins de jaune que de rouge et de bleu).
Répéter un schéma avec TileMode
Chaque pinceau de dégradé peut définir un TileMode
. Vous ne remarquerez peut-être pas TileMode
si vous n'avez pas défini de début et de fin pour le dégradé, car il remplira par défaut toute la surface. TileMode
ne met en mosaïque le dégradé que si la zone est plus grande que la taille du pinceau.
Le code suivant répète le modèle de gradient quatre fois, car endX
est défini sur 50.dp
et la taille sur 200.dp
:
val listColors = listOf(Color.Yellow, Color.Red, Color.Blue) val tileSize = with(LocalDensity.current) { 50.dp.toPx() } Box( modifier = Modifier .requiredSize(200.dp) .background( Brush.horizontalGradient( listColors, endX = tileSize, tileMode = TileMode.Repeated ) ) )
Voici un tableau détaillant le fonctionnement des différents modes mosaïque pour l'exemple HorizontalGradient
ci-dessus :
Mode mosaïque | Sortie |
---|---|
TileMode.Repeated : la bordure est répétée de la dernière couleur à la première. |
|
TileMode.Mirror : la bordure est mise en miroir de la dernière couleur à la première. |
|
TileMode.Clamp : la bordure est fixée à la couleur finale. La couleur la plus proche est ensuite affichée pour le reste de la région. |
|
TileMode.Decal : effectue le rendu uniquement jusqu'à la taille des limites. TileMode.Decal exploite le noir transparent pour échantillonner le contenu en dehors des limites d'origine, tandis que TileMode.Clamp échantillonne la couleur des bordures. |
TileMode
fonctionne de manière similaire pour les autres dégradés directionnels, la différence étant la direction de la répétition.
Modifier la taille du pinceau
Si vous connaissez la taille de la zone dans laquelle le traçage du pinceau aura lieu, vous pouvez définir la mosaïque endX
comme indiqué ci-dessus dans la section TileMode
. Si vous êtes dans un élément DrawScope
, vous pouvez utiliser sa propriété size
pour obtenir la taille de la zone.
Si vous ne connaissez pas la taille de votre zone de dessin (par exemple, si Brush
est affecté au texte), vous pouvez étendre Shader
et utiliser la taille de la zone de dessin dans createShader
.
Dans cet exemple, divisez la taille par 4 pour répéter le modèle quatre fois :
val listColors = listOf(Color.Yellow, Color.Red, Color.Blue) val customBrush = remember { object : ShaderBrush() { override fun createShader(size: Size): Shader { return LinearGradientShader( colors = listColors, from = Offset.Zero, to = Offset(size.width / 4f, 0f), tileMode = TileMode.Mirror ) } } } Box( modifier = Modifier .requiredSize(200.dp) .background(customBrush) )
Vous pouvez également modifier la taille de pinceau de n'importe quel autre dégradé, tel que le dégradé radial. Si vous ne spécifiez pas de taille ni de centre, le dégradé occupera les limites complètes de DrawScope
, et le centre du dégradé radial correspondra par défaut au centre des limites DrawScope
. Le centre du dégradé radial apparaîtra alors au centre de la dimension la plus petite (largeur ou hauteur) :
Box( modifier = Modifier .fillMaxSize() .background( Brush.radialGradient( listOf(Color(0xFF2be4dc), Color(0xFF243484)) ) ) )
Lorsque le dégradé radial est modifié pour définir la taille du rayon sur la dimension maximale, vous pouvez constater qu'il produit un meilleur effet de dégradé radial :
val largeRadialGradient = object : ShaderBrush() { override fun createShader(size: Size): Shader { val biggerDimension = maxOf(size.height, size.width) return RadialGradientShader( colors = listOf(Color(0xFF2be4dc), Color(0xFF243484)), center = size.center, radius = biggerDimension / 2f, colorStops = listOf(0f, 0.95f) ) } } Box( modifier = Modifier .fillMaxSize() .background(largeRadialGradient) )
Notez que la taille réelle transmise pour créer le nuanceur est déterminée à partir de l'endroit où elle est appelée. Par défaut, Brush
réaffecte son Shader
en interne si la taille est différente de celle de la dernière création de l'élément Brush
, ou si un objet d'état utilisé lors de la création du nuanceur a changé.
Le code suivant crée le nuanceur trois fois avec des tailles différentes, à mesure que la taille de la zone de dessin change :
val colorStops = arrayOf( 0.0f to Color.Yellow, 0.2f to Color.Red, 1f to Color.Blue ) val brush = Brush.horizontalGradient(colorStops = colorStops) Box( modifier = Modifier .requiredSize(200.dp) .drawBehind { drawRect(brush = brush) // will allocate a shader to occupy the 200 x 200 dp drawing area inset(10f) { /* Will allocate a shader to occupy the 180 x 180 dp drawing area as the inset scope reduces the drawing area by 10 pixels on the left, top, right, bottom sides */ drawRect(brush = brush) inset(5f) { /* will allocate a shader to occupy the 170 x 170 dp drawing area as the inset scope reduces the drawing area by 5 pixels on the left, top, right, bottom sides */ drawRect(brush = brush) } } } )
Utiliser une image en tant que pinceau
Pour utiliser un ImageBitmap en tant que Brush
, chargez l'image en tant qu'ImageBitmap
et créez un pinceau ImageShader
:
val imageBrush = ShaderBrush(ImageShader(ImageBitmap.imageResource(id = R.drawable.dog))) // Use ImageShader Brush with background Box( modifier = Modifier .requiredSize(200.dp) .background(imageBrush) ) // Use ImageShader Brush with TextStyle Text( text = "Hello Android!", style = TextStyle( brush = imageBrush, fontWeight = FontWeight.ExtraBold, fontSize = 36.sp ) ) // Use ImageShader Brush with DrawScope#drawCircle() Canvas(onDraw = { drawCircle(imageBrush) }, modifier = Modifier.size(200.dp))
Le pinceau est appliqué à différents types de dessins : arrière-plan, texte et canevas. Vous obtenez le résultat suivant :
Notez que le texte est désormais également affiché à l'aide d'ImageBitmap
afin de peindre les pixels du texte.
Exemple avancé: pinceau personnalisé
Pinceau RuntimeShader
AGSL
AGSL offre un sous-ensemble des fonctionnalités du nuanceur GLSL. Les nuanceurs peuvent être écrits en langage AGSL et utilisés avec un pinceau dans Compose.
Pour créer un pinceau de nuanceur, définissez-le d'abord comme chaîne de nuanceur AGSL :
@Language("AGSL") val CUSTOM_SHADER = """ uniform float2 resolution; layout(color) uniform half4 color; layout(color) uniform half4 color2; half4 main(in float2 fragCoord) { float2 uv = fragCoord/resolution.xy; float mixValue = distance(uv, vec2(0, 1)); return mix(color, color2, mixValue); } """.trimIndent()
Le nuanceur ci-dessus utilise deux couleurs d'entrée, calcule la distance à partir de l'angle inférieur gauche (vec2(0, 1)
) de la zone de dessin et effectue un mix
entre les deux couleurs en fonction de la distance. Cela produit un effet de dégradé.
Créez ensuite le pinceau du nuanceur et définissez les uniformes pour la resolution
(la taille de la zone de dessin, ainsi que les éléments color
et color2
que vous souhaitez utiliser comme entrées pour votre dégradé) :
val Coral = Color(0xFFF3A397) val LightYellow = Color(0xFFF8EE94) @RequiresApi(Build.VERSION_CODES.TIRAMISU) @Composable @Preview fun ShaderBrushExample() { Box( modifier = Modifier .drawWithCache { val shader = RuntimeShader(CUSTOM_SHADER) val shaderBrush = ShaderBrush(shader) shader.setFloatUniform("resolution", size.width, size.height) onDrawBehind { shader.setColorUniform( "color", android.graphics.Color.valueOf( LightYellow.red, LightYellow.green, LightYellow .blue, LightYellow.alpha ) ) shader.setColorUniform( "color2", android.graphics.Color.valueOf( Coral.red, Coral.green, Coral.blue, Coral.alpha ) ) drawRect(shaderBrush) } } .fillMaxWidth() .height(200.dp) ) }
En exécutant cette commande, vous pouvez voir ce qui suit à l'écran :
Il est intéressant de noter que vous pouvez réaliser bien plus de tâches avec les nuanceurs qu'avec les dégradés, car ils reposent sur des calculs mathématiques. Pour en savoir plus sur AGSL, consultez cette documentation.
Ressources supplémentaires
Pour voir d'autres exemples d'utilisation du pinceau dans Compose, consultez les ressources suivantes :
- Animer le pinceau de coloration du texte dans Compose 🖌️
- Graphiques et mises en page personnalisés dans Compose : Sommet des développeurs Android 2022
- Exemple JetLagged : pinceau RuntimeShader
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé.
- Modificateurs graphiques
- Éléments graphiques dans Compose
- Styler le texte