Jetpack Compose propose une implémentation de Material Design, un système de conception complet permettant de créer des interfaces numériques. Les composants Material Design (boutons, cartes, interrupteurs, etc.) sont basés sur la thématisation Material, un moyen systématique de personnaliser Material Design pour mieux refléter la marque de votre produit. Un thème Material inclut les attributs couleur, typographie et forme. Lorsque vous personnalisez ces attributs, vos modifications sont automatiquement répercutées dans les composants que vous utilisez pour créer votre application.
Jetpack Compose implémente ces concepts avec le composable MaterialTheme
:
MaterialTheme( colors = // ... typography = // ... shapes = // ... ) { // app content }
Configurez les paramètres que vous transmettez à MaterialTheme
pour appliquer un thème à votre application.
Figure 1. La première capture d'écran montre une application qui ne configure pas MaterialTheme
. Elle utilise donc le style par défaut. La deuxième capture d'écran montre une application qui transmet des paramètres à MaterialTheme
pour personnaliser le style.
Couleur
Les couleurs sont modélisées dans Compose avec la classe Color
, qui est une classe simple de stockage de données.
val Red = Color(0xffff0000) val Blue = Color(red = 0f, green = 0f, blue = 1f)
Bien que vous puissiez les organiser comme vous le souhaitez (en tant que constantes de premier niveau, dans un singleton ou définies de manière intégrée), nous vous recommandons vivement de spécifier des couleurs dans votre thème et de les récupérer à partir de cet endroit. Cela facilite la prise en charge des thèmes sombres et des thèmes imbriqués.
Figure 2. Système de couleurs Material.
Compose fournit la classe Colors
pour modéliser le système de couleurs Material. Colors
fournit des fonctions de compilateur pour créer des ensembles de couleurs claires ou sombres :
private val Yellow200 = Color(0xffffeb46) private val Blue200 = Color(0xff91a4fc) // ... private val DarkColors = darkColors( primary = Yellow200, secondary = Blue200, // ... ) private val LightColors = lightColors( primary = Yellow500, primaryVariant = Yellow400, secondary = Blue700, // ... )
Après avoir défini vos Colors
, vous pouvez les transmettre à un MaterialTheme
:
MaterialTheme( colors = if (darkTheme) DarkColors else LightColors ) { // app content }
Utiliser les couleurs du thème
Vous pouvez récupérer les Colors
fournies au composable MaterialTheme
à l'aide de MaterialTheme.colors
.
Text( text = "Hello theming", color = MaterialTheme.colors.primary )
Couleur de la surface et du contenu
De nombreux composants acceptent une paire de couleurs et des couleurs de contenu :
Surface( color = MaterialTheme.colors.surface, contentColor = contentColorFor(color), // ... ) { /* ... */ } TopAppBar( backgroundColor = MaterialTheme.colors.primarySurface, contentColor = contentColorFor(backgroundColor), // ... ) { /* ... */ }
Cela vous permet non seulement de définir la couleur d'un composable, mais aussi d'utiliser une couleur par défaut pour le contenu, c'est-à-dire les composables qu'il contient. De nombreux composables utilisent cette couleur de contenu par défaut. Par exemple, Text
base sa couleur sur celle du contenu de son parent, et Icon
utilise cette couleur pour définir sa teinte.
Figure 3. Définir différentes couleurs d'arrière-plan génère différentes couleurs de texte et d'icône.
La méthode contentColorFor()
récupère la couleur "on" appropriée pour toutes les couleurs du thème. Par exemple, si vous définissez un arrière-plan de couleur primary
pour la Surface
, cette fonction est utilisée pour définir onPrimary
comme couleur de contenu. Si vous choisissez une couleur d'arrière-plan différente de celle du thème, vous devez également spécifier une couleur de contenu appropriée. Utilisez LocalContentColor
pour récupérer la couleur de contenu préférée de l'arrière-plan actuel, à une position donnée dans la hiérarchie.
Valeurs alpha du contenu
Vous souhaitez souvent varier la mise en valeur du contenu pour insister sur l'importance et fournir une hiérarchie visuelle. Les recommandations de lisibilité du texte Material Design conseillent d'employer différents niveaux d'opacité pour indiquer différents niveaux d'importance.
Jetpack Compose met cela en œuvre via LocalContentAlpha
.
Vous pouvez spécifier une valeur alpha du contenu pour une hiérarchie en fournissant une valeur pour ce CompositionLocal
.
Les composables imbriqués peuvent utiliser cette valeur pour appliquer le traitement alpha à leur contenu.
Par exemple, Text
et Icon
utilisent par défaut la combinaison de LocalContentColor
ajustée pour utiliser LocalContentAlpha
. Material spécifie des valeurs alpha standards (high
, medium
, disabled
), qui sont modélisées par l'objet ContentAlpha
.
// By default, both Icon & Text use the combination of LocalContentColor & // LocalContentAlpha. De-emphasize content by setting content alpha CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.medium) { Text( // ... ) } CompositionLocalProvider(LocalContentAlpha provides ContentAlpha.disabled) { Icon( // ... ) Text( // ... ) }
Pour en savoir plus sur CompositionLocal
, consultez le guide Données à champ d'application local avec CompositionLocal.
Figure 4. Appliquez différents niveaux d'accentuation du texte pour communiquer visuellement la hiérarchie des informations. La première ligne du texte correspond au titre et comporte les informations les plus importantes. Elle utilise donc ContentAlpha.high
. La deuxième contient des métadonnées moins importantes et utilise donc ContentAlpha.medium
.
Thème sombre
Dans Compose, vous implémentez des thèmes clair et sombre en fournissant différents ensembles de Colors
pour le composable MaterialTheme
:
@Composable fun MyTheme( darkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit ) { MaterialTheme( colors = if (darkTheme) DarkColors else LightColors, /*...*/ content = content ) }
Dans cet exemple, MaterialTheme
est encapsulé dans sa propre fonction modulable, qui accepte un paramètre spécifiant s'il faut ou non utiliser un thème sombre. Dans ce cas, la fonction obtient la valeur par défaut pour darkTheme
en interrogeant le paramètre de thème de l'appareil.
Vous pouvez utiliser ce code pour vérifier si les Colors
actuelles sont claires ou sombres :
val isLightTheme = MaterialTheme.colors.isLight Icon( painterResource( id = if (isLightTheme) { R.drawable.ic_sun_24 } else { R.drawable.ic_moon_24 } ), contentDescription = "Theme" )
Superpositions d'élévation
Dans Material, les surfaces des thèmes sombres d'élévation plus élevée reçoivent des superpositions d'élévation, ce qui éclaircit leur arrière-plan. Plus l'élévation d'une surface est élevée (c'est-à-dire plus proche d'une source de lumière implicite), plus cette surface est claire.
Ces superpositions sont appliquées automatiquement par le composable Surface
lors de l'utilisation de couleurs sombres, et pour tout autre composable Material qui utilise une surface :
Surface( elevation = 2.dp, color = MaterialTheme.colors.surface, // color will be adjusted for elevation /*...*/ ) { /*...*/ }
Figure 5. Les cartes et la barre de navigation inférieure utilisent toutes deux la couleur surface
comme arrière-plan. Étant donné que les cartes et la barre de navigation inférieure sont situées à des élévations différentes au-dessus de l'arrière-plan, les couleurs sont légèrement différentes. Les cartes sont plus claires que l'arrière-plan et la barre de navigation inférieure est plus claire que les cartes.
Pour les scénarios personnalisés qui n'impliquent pas de Surface
, utilisez LocalElevationOverlay
, un CompositionLocal
contenant l'ElevationOverlay
utilisée par les composants Surface
:
// Elevation overlays // Implemented in Surface (and any components that use it) val color = MaterialTheme.colors.surface val elevation = 4.dp val overlaidColor = LocalElevationOverlay.current?.apply( color, elevation )
Pour désactiver les superpositions d'élévation, indiquez null
au point souhaité dans une hiérarchie composable :
MyTheme { CompositionLocalProvider(LocalElevationOverlay provides null) { // Content without elevation overlays } }
Touches de couleurs limitées
Dans la plupart des cas, Material Design recommande d'appliquer des touches de couleurs limitées pour les thèmes sombres en utilisant plutôt la couleur surface
que la couleur primary
. Les composables Material tels que TopAppBar
et BottomNavigation
implémentent ce comportement par défaut.
Figure 6. Thème sombre Material avec des touches de couleur limitées. La barre d'application supérieure utilise la couleur principale du thème clair et la couleur de surface du thème sombre.
Pour les scénarios personnalisés, utilisez la propriété d'extension primarySurface
:
Surface( // Switches between primary in light theme and surface in dark theme color = MaterialTheme.colors.primarySurface, /*...*/ ) { /*...*/ }
Typographie
Material définit un système type, qui vous encourage à utiliser un petit nombre de styles nommés sémantiquement.
Figure 7. Le système de type Material.
Compose implémente le système de type avec les classes Typography
, TextStyle
et liées à la police. Le constructeur Typography
propose des valeurs par défaut pour chaque style afin que vous puissiez omettre ceux que vous ne souhaitez pas personnaliser :
val raleway = FontFamily( Font(R.font.raleway_regular), Font(R.font.raleway_medium, FontWeight.W500), Font(R.font.raleway_semibold, FontWeight.SemiBold) ) val myTypography = Typography( h1 = TextStyle( fontFamily = raleway, fontWeight = FontWeight.W300, fontSize = 96.sp ), body1 = TextStyle( fontFamily = raleway, fontWeight = FontWeight.W600, fontSize = 16.sp ) /*...*/ ) MaterialTheme(typography = myTypography, /*...*/) { /*...*/ }
Si vous souhaitez utiliser la même police de caractères partout, spécifiez la defaultFontFamily parameter
et omettez la fontFamily
des éléments TextStyle
:
val typography = Typography(defaultFontFamily = raleway) MaterialTheme(typography = typography, /*...*/) { /*...*/ }
Utiliser des styles de texte
Les TextStyle
sont accessibles via MaterialTheme.typography
. Récupérez les TextStyle
comme suit :
Text( text = "Subtitle2 styled", style = MaterialTheme.typography.subtitle2 )
Figure 8. Utilisez une sélection de polices et de styles pour exprimer votre marque.
Forme
Material définit un système de formes qui vous permet de définir des formes pour les composants volumineux, moyens et petits.
Figure 9. Le système de formes Material.
Compose implémente le système de formes avec la classe Shapes
, qui vous permet de spécifier une CornerBasedShape
pour chaque catégorie de taille :
val shapes = Shapes( small = RoundedCornerShape(percent = 50), medium = RoundedCornerShape(0f), large = CutCornerShape( topStart = 16.dp, topEnd = 0.dp, bottomEnd = 0.dp, bottomStart = 16.dp ) ) MaterialTheme(shapes = shapes, /*...*/) { /*...*/ }
De nombreux composants utilisent ces formes par défaut. Par exemple : Button
, TextField
et FloatingActionButton
sont définis par défaut sur "petit", AlertDialog
sur "moyen", et ModalDrawer
sur "grand". Consultez la documentation de référence sur les schémas de forme pour le mappage complet.
Utiliser des formes
Les Shape
s sont accessibles via MaterialTheme.shapes
. Récupérez les Shape
s avec le code suivant :
Surface( shape = MaterialTheme.shapes.medium, /*...*/ ) { /*...*/ }
Figure 10. Utilisez des formes pour exprimer votre marque ou votre état.
Styles par défaut
Les styles par défaut pour les vues Android n'ont pas d'équivalent dans Compose. Vous pouvez fournir une fonctionnalité similaire en créant vos propres fonctions modulables de surcharge qui encapsulent les composants Material. Par exemple, pour créer un style de bouton, encapsulez un bouton dans votre fonction modulable, en définissant directement les paramètres que vous souhaitez modifier et en exposant les autres en tant que paramètres au composable associé.
@Composable fun MyButton( onClick: () -> Unit, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Button( colors = ButtonDefaults.buttonColors( backgroundColor = MaterialTheme.colors.secondary ), onClick = onClick, modifier = modifier, content = content ) }
Superpositions de thèmes
Vous pouvez obtenir l'équivalent des superpositions de thèmes d'Android Views dans Compose en imbriquant des composables MaterialTheme
. Comme MaterialTheme
utilise par défaut la valeur actuelle du thème pour les couleurs, la typographie et les formes, si un thème ne définit qu'un seul de ces paramètres, les autres conservent leurs valeurs par défaut.
De plus, lorsque vous migrez des écrans basés sur les vues Compose, faites attention aux utilisations de l'attribut android:theme
. Vous aurez probablement besoin d'un nouveau MaterialTheme
dans cette partie de l'arborescence de l'UI Compose.
Dans cet exemple, l'écran d'informations utilise un thème rose (PinkTheme
) pour la majeure partie de l'écran, puis un thème bleu (BlueTheme
) pour la section associée. Voir la capture d'écran et le code ci-dessous.
Figure 11 : Thèmes imbriqués.
@Composable fun DetailsScreen(/* ... */) { PinkTheme { // other content RelatedSection() } } @Composable fun RelatedSection(/* ... */) { BlueTheme { // content } }
États des composants
Les composants Material avec lesquels vous pouvez interagir (cliqué, activé/désactivé, etc.) peuvent se trouver dans différents états visuels. Les états incluent : activé, désactivé, appuyé, etc.
Les composables comportent souvent un paramètre enabled
. Définir sa valeur sur false
empêche toute interaction et modifie des propriétés telles que la couleur et l'élévation pour transmettre visuellement l'état du composant.
Figure 12. Bouton avec enabled = true
(à gauche) et enabled = false
(à droite).
Dans la plupart des cas, vous pouvez conserver les valeurs par défaut pour les valeurs telles que la couleur et l'élévation. Si vous souhaitez configurer des valeurs utilisées dans différents états, des classes et des fonctions pratiques sont disponibles. Consultez l'exemple de bouton ci-dessous :
Button( onClick = { /* ... */ }, enabled = true, // Custom colors for different states colors = ButtonDefaults.buttonColors( backgroundColor = MaterialTheme.colors.secondary, disabledBackgroundColor = MaterialTheme.colors.onBackground .copy(alpha = 0.2f) .compositeOver(MaterialTheme.colors.background) // Also contentColor and disabledContentColor ), // Custom elevation for different states elevation = ButtonDefaults.elevation( defaultElevation = 8.dp, disabledElevation = 2.dp, // Also pressedElevation ) ) { /* ... */ }
Figure 13. Bouton avec enabled = true
(à gauche) et enabled = false
(à droite), avec des valeurs de couleur et d'élévation ajustées.
Ondulations
Material Components utilise des ondulations pour indiquer qu'ils font l'objet d'une interaction. Si vous utilisez MaterialTheme
dans votre hiérarchie, une ondulation (Ripple
) sera utilisée comme Indication
par défaut dans des modificateurs tels que clickable
et indication
.
Dans la plupart des cas, vous pouvez conserver la Ripple
par défaut. Si vous souhaitez configurer leur apparence, vous pouvez utiliser RippleTheme
pour modifier des propriétés telles que la couleur et la l'alpha.
Vous pouvez étendre RippleTheme
et utiliser les fonctions utilitaires defaultRippleColor
et defaultRippleAlpha
. Vous pouvez ensuite fournir votre thème d'ondulation personnalisé dans votre hiérarchie à l'aide de LocalRippleTheme
:
@Composable fun MyApp() { MaterialTheme { CompositionLocalProvider( LocalRippleTheme provides SecondaryRippleTheme ) { // App content } } } @Immutable private object SecondaryRippleTheme : RippleTheme { @Composable override fun defaultColor() = RippleTheme.defaultRippleColor( contentColor = MaterialTheme.colors.secondary, lightTheme = MaterialTheme.colors.isLight ) @Composable override fun rippleAlpha() = RippleTheme.defaultRippleAlpha( contentColor = MaterialTheme.colors.secondary, lightTheme = MaterialTheme.colors.isLight ) }
Figure 14. Boutons avec différentes valeurs d'ondulation fournies par RippleTheme
.
En savoir plus
Pour en savoir plus sur la thématisation Material dans Compose, consultez les ressources supplémentaires suivantes.
Ateliers de programmation
Vidéos
- Material You in Jetpack Compose (Material You dans Jetpack Compose)
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé
- Systèmes de conception personnalisés dans Compose
- Passer de Material 2 à Material 3 dans Compose
- Accessibilité dans Compose