Les dégradés en maillage créent des transitions de couleur complexes et multidirectionnelles à l'aide d'une grille 2D de patchs. Contrairement aux dégradés linéaires ou radiaux, les dégradés en maillage interpolent les couleurs de manière fluide sur une grille. Utilisez-les pour créer des éléments esthétiques fluides et organiques 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 zones le long des axes vertical et horizontal. Une grille de
rowsetcolumnscontient (rows+1)×(columns+1) sommets. Par exemple, un maillage 1x1 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ées où
(0f, 0f)représente le coin supérieur gauche et(1f, 1f)le coin inférieur droit des limites du dessin. - 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 correctifs. Chaque cellule de 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 pour des transitions 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 à l'intérieur du 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 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 soient 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 3x3, ce qui signifie que 16 points doivent être spécifiés, avec les points du milieu 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 mutable. 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) )