Les dégradés de maillage créent des transitions de couleurs complexes et multidirectionnelles à l'aide d'une grille 2D de patchs. Contrairement aux dégradés linéaires ou radiaux, les dégradés de maillage interpolent les couleurs de manière fluide sur une grille 2D. Utilisez des dégradés de maillage au lieu d'empiler plusieurs pinceaux radialGradient ou linearGradient lorsque vous créez des arrière-plans fluides, organiques ou multipoints dans votre interface utilisateur.
Concepts clés
Pour créer un dégradé de maillage, définissez les dimensions de la grille, les sommets et les transitions de couleur entre les points :
- Dimensions de la grille : le maillage est divisé en patchs le long des axes vertical et horizontal. Une grille de
rowsetcolumnscontient (lignes+1)×(colonnes+1) sommets. Par exemple, un maillage 1 x 1 se compose de quatre sommets formant un patch. - Coordonnées normalisées : toutes les positions des sommets utilisent un système de coordonnées normalisé où
(0f, 0f)représente l'angle supérieur gauche et(1f, 1f)l'angle inférieur droit des limites de tracé. - Points de contrôle de Bézier (tangentes) : chaque sommet contient jusqu'à quatre points de contrôle de Bézier facultatifs. Ces tangentes spécifient la courbure des bords entre les sommets voisins. Si vous utilisez
Offset.Unspecified, Compose déduit les tangentes pour assurer des transitions fluides entre les patchs. Chaque cellule de la grille formée par quatre sommets et leurs points de contrôle génère un patch de Bézier. - Interpolation des couleurs : le framework calcule les couleurs entre les sommets principaux. Définissez
hasBicubicColorsurtruepour l'interpolation Catmull-Rom afin d'obtenir des changements de couleur plus fluides, ou surfalsepour l'interpolation bilinéaire.
Dessiner avec MeshGradientPainter
Dans Jetpack Compose, utilisez MeshGradientPainter pour afficher un dégradé de maillage. MeshGradientPainter dessine sur le canevas.
Créer un dégradé de maillage simple
Pour créer un dégradé de maillage statique de base, initialisez un MeshGradientPainter en spécifiant ses dimensions et en utilisant la fonction setVertex dans le bloc de configuration pour positionner vos points d'angle et leur attribuer des couleurs.
val rows = 1 val columns = 1 val gradientPainter = remember { MeshGradientPainter(rows, columns) { // Parameters: row, column, position, color setVertex(0, 0, Offset(0f, 0f), Color.Red) // Top-Left setVertex(0, 1, Offset(1f, 0f), Color.Blue) // Top-Right setVertex(1, 0, Offset(0f, 1f), Color.Green) // Bottom-Left setVertex(1, 1, Offset(1f, 1f), Color.Yellow) // Bottom-Right } } Box( modifier = modifier .aspectRatio(16/9f) .fillMaxWidth() .paint(gradientPainter) )
Utiliser des points de contrôle de Bézier spécifiques
Par défaut, le générateur de maillage gère les calculs complexes pour que les transitions de la grille restent fluides. Toutefois, vous pouvez personnaliser explicitement les tangentes sur n'importe quel sommet si vous souhaitez pousser, tirer ou pincer de manière sélective certaines sections de couleur.
Les décalages de contrôle sont mesurés par rapport à la position du sommet hôte.
val customTangentPainter = remember { MeshGradientPainter(rows = 1, columns = 1) { // Tweak the top-left vertex to curve outwards to the right and bottom setVertex( row = 0, column = 0, position = Offset(0f, 0f), color = Color.Magenta, rightControlPoint = Offset(0.4f, 0.1f), bottomControlPoint = Offset(0.1f, 0.4f) ) // Other points can remain unspecified to use default inferred fallback tangents setVertex(0, 1, Offset(1f, 0f), Color.Cyan) setVertex(1, 0, Offset(0f, 1f), Color.Blue) setVertex(1, 1, Offset(1f, 1f), Color.Black) } } Box( modifier = modifier .aspectRatio(16/9f) .fillMaxWidth() .paint(customTangentPainter) )
Créer des grilles avancées
Cet exemple montre une grille de 3 par 3, ce qui signifie qu'il y a 16 points à spécifier, les points du milieu étant définis avec des décalages différents :
val points = remember { listOf( Offset(0.0f, 0.0f), Offset(0.3f, 0.0f), Offset(0.7f, 0.0f), Offset(1.0f, 0.0f), Offset(0.0f, 0.3f), Offset(0.2f, 0.4f), Offset(0.7f, 0.2f), Offset(1.0f, 0.3f), Offset(0.0f, 0.7f), Offset(0.3f, 0.8f), Offset(0.7f, 0.6f), Offset(1.0f, 0.7f), Offset(0.0f, 1.0f), Offset(0.3f, 1.0f), Offset(0.7f, 1.0f), Offset(1.0f, 1.0f) ) } val gradientPainter = remember { MeshGradientPainter(rows = 3, columns = 3) { // Row 0 setVertex(0, 0, points[0], yellow) setVertex(0, 1, points[1], orange) setVertex(0, 2, points[2], yellow) setVertex(0, 3, points[3], purple) // Row 1 setVertex(1, 0, points[4], pink) setVertex(1, 1, points[5], yellow) setVertex(1, 2, points[6], pink) setVertex(1, 3, points[7], purple) // Row 2 setVertex(2, 0, points[8], indigo) setVertex(2, 1, points[9], pink) setVertex(2, 2, points[10], purple) setVertex(2, 3, points[11], indigo) // Row 3 setVertex(3, 0, points[12], purple) setVertex(3, 1, points[13], indigo) setVertex(3, 2, points[14], pink) setVertex(3, 3, points[15], yellow) } } Box( modifier = modifier.padding(32.dp) .aspectRatio(16 / 9f) .fillMaxWidth() .paint(gradientPainter) // ... )
Animer un dégradé de maillage
Étant donné que le paramètre lambda block de MeshGradientPainter est exécuté dans un DrawScope, il peut lire et observer l'état modifiable. Vous pouvez animer des positions ou des couleurs au fil du temps sans réallouer de nuanceurs ni de bitmaps.
val infiniteTransition = rememberInfiniteTransition(label = "meshMovement") val animatedOffset by infiniteTransition.animateFloat( initialValue = -0.1f, targetValue = 0.1f, animationSpec = infiniteRepeatable( animation = tween(2500, easing = LinearEasing), repeatMode = RepeatMode.Reverse ), label = "offset" ) val coral = Color(255, 90, 90) val peach = Color(255, 139, 90) val amber = Color(255, 169, 90) val sunshine = Color(255, 212, 90) val indigo = Color(0xFF5856D6) val pink = Color(0xFFFF2D55) val gradientPainter = remember { MeshGradientPainter(rows = 3, columns = 3) { // Row 0 setVertex(0, 0, Offset(0.0f, 0.0f), indigo) setVertex(0, 1, Offset(0.3f, 0.0f), peach) setVertex(0, 2, Offset(0.7f, 0.0f), amber) setVertex(0, 3, Offset(1.0f, 0.0f), sunshine) // Row 1 setVertex(1, 0, Offset(0.0f, 0.3f), pink) setVertex(1, 1, Offset(0.2f, 0.4f) + Offset(animatedOffset, animatedOffset), coral) setVertex(1, 2, Offset(0.7f, 0.2f) + Offset(animatedOffset, animatedOffset), peach) setVertex(1, 3, Offset(1.0f, 0.3f), indigo) // Row 2 setVertex(2, 0, Offset(0.0f, 0.7f), coral) setVertex(2, 1, Offset(0.3f, 0.8f) + Offset(animatedOffset, 0f), pink) setVertex(2, 2, Offset(0.7f, 0.6f) + Offset(animatedOffset, 0f), sunshine) setVertex(2, 3, Offset(1.0f, 0.7f), amber) // Row 3 setVertex(3, 0, Offset(0.0f, 1.0f), sunshine) setVertex(3, 1, Offset(0.3f, 1.0f), amber) setVertex(3, 2, Offset(0.7f, 1.0f), pink) setVertex(3, 3, Offset(1.0f, 1.0f), indigo) } } Box( modifier = modifier.padding(32.dp) .safeContentPadding() .aspectRatio(16 / 9f) .fillMaxWidth() .paint(gradientPainter) )