Cette page offre une vue d'ensemble des couches architecturales qui composent Jetpack Compose, ainsi que les principes fondamentaux sur lesquels repose cette architecture.
Jetpack Compose n'est pas un projet monolithique unique. Il se compose de plusieurs modules assemblés pour former un ensemble. Comprendre les différents modules de Jetpack Compose vous permet :
- d'utiliser le niveau d'abstraction approprié pour créer votre application ou votre bibliothèque ;
- de déterminer à quel moment vous pouvez "passer à un niveau inférieur" pour plus de contrôle ou de personnalisation ;
- de minimiser vos dépendances.
Couches
Les principales couches de Jetpack Compose sont les suivantes :
Figure 1 : Principales couches de Jetpack Compose
Chaque couche repose sur les niveaux inférieurs et combine des fonctionnalités pour créer des composants de niveau supérieur. Chaque couche repose sur les API publiques des couches inférieures pour vérifier les limites du module et vous permettre de remplacer n'importe quelle couche si nécessaire. Examinons ces couches de bas en haut.
- Runtime (durée d'exécution)
- Ce module présente les principes de base de l'environnement d'exécution Compose, tels que
remember
,mutableStateOf
, l'annotation@Composable
etSideEffect
. Vous pourriez envisager de vous appuyer directement sur cette couche si vous n'avez besoin que des fonctionnalités de gestion des arborescences de Compose, et non de son interface utilisateur. - UI (interface utilisateur)
- La couche de l'interface utilisateur est composée de plusieurs modules (
ui-text
,ui-graphics
,ui-tooling
, etc.). Ces modules implémentent les principes de base du kit d'interface utilisateur, tels queLayoutNode
,Modifier
, les gestionnaires d'entrée, les mises en page personnalisées et le dessin. Vous pourriez envisager de vous appuyer sur cette couche si vous n'avez besoin que des concepts fondamentaux d'un kit d'interface utilisateur. - Foundation (fondation)
- Ce module fournit des composants qui ne dépendent pas du système de conception pour l'interface utilisateur de Compose, tels que
Row
etColumn
,LazyColumn
, la reconnaissance de gestes spécifiques, etc. Vous pourriez envisager de vous appuyer sur la couche de fondation pour créer votre propre système de conception. - Material
- Ce module permet d'implémenter le système Material Design pour l'interface utilisateur de Compose. Il fournit un système de thématisation, des composants stylisés, des indications d'ondes et des icônes. Appuyez-vous sur cette couche lorsque vous utilisez Material Design dans votre application.
Principes de conception
L'un des principes directeurs de Jetpack Compose est de fournir de petites fonctionnalités spécifiques qui peuvent être assemblées (ou composées) plutôt que quelques composants monolithiques. Cette approche présente plusieurs avantages.
Contrôle
Les composants de niveau supérieur ont tendance à en faire plus, mais limitent votre niveau de contrôle direct. Si vous avez besoin de plus de contrôle, vous pouvez "passer à un niveau inférieur" pour utiliser un composant d'un niveau plus bas.
Par exemple, si vous souhaitez animer la couleur d'un composant, vous pourriez utiliser l'API animateColorAsState
:
val color = animateColorAsState(if (condition) Color.Green else Color.Red)
Si vous souhaitez que ce composant soit grisé au démarrage, vous ne pouvez pas le faire avec cette API. À la place, vous pouvez passer au niveau inférieur pour utiliser l'API Animatable
:
val color = remember { Animatable(Color.Gray) } LaunchedEffect(condition) { color.animateTo(if (condition) Color.Green else Color.Red) }
L'API animateColorAsState
de niveau supérieur est elle-même basée sur l'API Animatable
de niveau inférieur. L'utilisation de l'API de niveau inférieur est plus complexe, mais offre plus de contrôle. Choisissez le niveau d'abstraction qui correspond le mieux à vos besoins.
Personnalisation
L'assemblage de composants de niveau supérieur à partir de composants inférieurs facilite grandement la personnalisation des composants, si besoin. Prenons l'exemple de l'implémentation de Button
(bouton) fournie par la couche Material :
@Composable fun Button( // … content: @Composable RowScope.() -> Unit ) { Surface(/* … */) { CompositionLocalProvider(/* … */) { // set LocalContentAlpha ProvideTextStyle(MaterialTheme.typography.button) { Row( // … content = content ) } } } }
Un Button
est assemblé à partir de quatre éléments :
Un
Surface
Material qui fournit l'arrière-plan, la forme, la gestion des clics, etc.Un
CompositionLocalProvider
qui modifie la valeur alpha du contenu lorsque le bouton est activé ou désactivéUn
ProvideTextStyle
qui définit le style de texte par défaut à utiliserUn
Row
qui fournit la règle de mise en page par défaut pour le contenu du bouton.
Nous avons omis certains paramètres et commentaires pour clarifier la structure, mais l'ensemble du composant ne comporte qu'une quarantaine de lignes de code, car il assemble simplement ces quatre composants pour implémenter le bouton. Les composants tels que Button
sont définis par rapport aux paramètres qu'ils exposent, ce qui permet de se limiter aux personnalisations courantes plutôt que de multiplier les paramètres susceptibles de rendre plus difficile l'utilisation d'un composant. Les composants Material, par exemple, proposent des personnalisations spécifiées dans le système Material Design, ce qui permet de suivre facilement les principes de Material Design.
Toutefois, si vous souhaitez effectuer une personnalisation au-delà des paramètres d'un composant, vous pouvez "passer au niveau inférieur" et dupliquer un composant. Par exemple, Material Design indique que l'arrière-plan des boutons doit être uni. Si vous avez besoin d'un arrière-plan dégradé, cette option n'est pas compatible avec les paramètres Button
. Dans ce cas, vous pouvez utiliser l'implémentation Material de Button
comme référence et créer votre propre composant :
@Composable fun GradientButton( // … background: List<Color>, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Row( // … modifier = modifier .clickable(onClick = {}) .background( Brush.horizontalGradient(background) ) ) { CompositionLocalProvider(/* … */) { // set material LocalContentAlpha ProvideTextStyle(MaterialTheme.typography.button) { content() } } } }
L'implémentation ci-dessus continue à utiliser les composants de la couche Material, tels que les concepts de la valeur alpha du contenu actuel et le style de texte actuel. Cependant, elle remplace la Surface
Material par une Row
et le stylise pour obtenir l'apparence souhaitée.
Si vous ne souhaitez pas du tout utiliser de concepts de Material, par exemple si vous créez votre propre système de conception sur mesure, vous pouvez choisir de n'utiliser que des composants de la couche de fondation:
@Composable fun BespokeButton( // … backgroundColor: Color, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Row( // … modifier = modifier .clickable(onClick = {}) .background(backgroundColor) ) { // No Material components used content() } }
Jetpack Compose réserve les noms les plus simples aux composants de niveau supérieur. Par exemple, androidx.compose.material.Text
est basé sur androidx.compose.foundation.text.BasicText
.
Cela vous permet de mettre en place votre propre implémentation avec le nom le plus visible si vous souhaitez remplacer les niveaux supérieurs.
Choisir la bonne abstraction
La philosophie de Compose, qui consiste à créer des composants par couche et réutilisables, implique de ne pas toujours chercher les composants fondamentaux de niveau inférieur. De nombreux composants de niveau supérieur offrent non seulement plus de fonctionnalités, mais implémentent souvent de bonnes pratiques telles que la prise en charge de l'accessibilité.
Par exemple, si vous souhaitez ajouter la prise en charge des gestes à votre composant personnalisé, vous pouvez partir de zéro en utilisant Modifier.pointerInput
, mais il existe d'autres composants de niveau supérieur, construits sur cette base et pouvant offrir un meilleur point de départ, tels que Modifier.draggable
, Modifier.scrollable
. ou Modifier.swipeable
.
En règle générale, privilégiez le composant de niveau supérieur offrant la fonctionnalité dont vous avez besoin pour bénéficier des bonnes pratiques qu'il comprend.
En savoir plus
Pour découvrir un exemple de création d'un système de conception personnalisé, consultez l'exemple Jetsnack.
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé
- Kotlin pour Jetpack Compose
- Listes et grilles
- Effets secondaires dans Compose