Dégradés de maillage

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.

Exemple de dégradé de maillage avec affichage de ses points de dégradé de maillage actuels.
Figure 1. Exemple de dégradé de maillage avec affichage de ses points de dégradé de maillage actuels.

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 rows et columns contient (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 hasBicubicColor sur true pour l'interpolation Catmull-Rom pour des transitions de couleur plus fluides, ou sur false pour 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)
)

Dégradé de maillage de base avec quatre couleurs définies à chaque angle
Figure 2. Dégradé de maillage de base avec quatre couleurs, chaque angle étant défini sur l'une des quatre.

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)
)

Dégradé de maillage avec un point incurvé en haut à gauche.
Figure 3. Arrondissez le sommet en haut à gauche avec un point de contrôle Bézier.

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)
        // ...
)

Dégradé de maillage avec des points de contrôle Bézier et des couleurs d'onde, et les points de maillage illustrés au-dessus.
Figure 4. Dégradé de maillage avec points de contrôle de Bézier et couleurs d'onde, et points de maillage illustrés au-dessus.

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)
)

Figure 5. Dégradé de maillage animé avec des points pour montrer l'animation.