Actualités des produits

Nouveautés de la version d'avril 2026 de Jetpack Compose

Temps de lecture : 5 min
Meghan Mehta
Developers Advocate, Android

Aujourd'hui, la version d'avril 2026 de Jetpack Compose est stable. Cette version contient la version 1.11 des modules Compose principaux (consultez le mapping BOM complet), des outils de débogage des éléments partagés, des événements du pavé tactile et plus encore. Nous avons également quelques API expérimentales que nous aimerions que vous testiez et sur lesquelles vous nous donniez votre avis.

Pour utiliser la version d'aujourd'hui, mettez à niveau votre version de la BOM Compose vers :

implementation(platform("androidx.compose:compose-bom:2026.04.01"))

Modifications apportées dans Compose 1.11.0

Exécution de coroutines dans les tests

Nous apportons une modification majeure à la façon dont Compose gère le timing des tests. Suite à la période d'activation annoncée dans Compose 1.10, les API de test v2 sont désormais celles par défaut, et les API v1 ont été abandonnées. Le changement clé concerne le coordinateur de test par défaut. Alors que les API v1 s'appuyaient sur UnconfinedTestDispatcher, qui exécutait les coroutines immédiatement, les API v2 utilisent StandardTestDispatcher. Cela signifie que lorsqu'une coroutine est lancée dans vos tests, elle est désormais mise en file d'attente et ne s'exécute que lorsque l'horloge virtuelle est avancée.

Cela imite mieux les conditions de production, éliminant efficacement les conditions de concurrence et rendant votre suite de tests beaucoup plus robuste et moins instable.

Pour vous assurer que vos tests sont conformes au comportement standard des coroutines et éviter de futurs problèmes de compatibilité, nous vous recommandons vivement de migrer votre suite de tests. Consultez notre guide de migration complet pour découvrir les mappages d'API et les correctifs courants.

Améliorations des éléments partagés et des outils d'animation

Nous avons également ajouté des outils de débogage visuel pratiques pour les éléments partagés et Modifier.animatedBounds. Vous pouvez désormais voir exactement ce qui se passe en coulisses (comme les limites cibles, les trajectoires d'animation et le nombre de correspondances trouvées). Il est ainsi beaucoup plus facile de comprendre pourquoi une transition ne se comporte pas comme prévu. Pour utiliser le nouvel outil, il vous suffit d'entourer votre SharedTransitionLayout avec le composable LookaheadAnimationVisualDebugging

LookaheadAnimationVisualDebugging(
    overlayColor = Color(0x4AE91E63),
    isEnabled = true,
    multipleMatchesColor = Color.Green,
    isShowKeylabelEnabled = false,
    unmatchedElementColor = Color.Red,
) {
    SharedTransitionLayout {
        CompositionLocalProvider(
            LocalSharedTransitionScope provides this,
        ) {
            // your content
        }
    }
}

Événements du pavé tactile

Nous avons amélioré la prise en charge de Compose pour les trackpads, comme les trackpads intégrés aux ordinateurs portables, les trackpads amovibles pour les tablettes ou les trackpads externes/virtuels. Les événements de base du pavé tactile seront désormais généralement considérés comme des événements PointerType.Mouse, ce qui permettra d'aligner le comportement de la souris et du pavé tactile pour mieux répondre aux attentes des utilisateurs. Auparavant, ces événements de pavé tactile étaient interprétés comme de faux doigts sur un écran tactile de PointerType.Touch, ce qui entraînait des expériences utilisateur déroutantes. Par exemple, cliquer et faire glisser avec un pavé tactile permettait de faire défiler la page au lieu de sélectionner du texte. En modifiant le type de pointeur de ces événements dans la dernière version de Compose, le fait de cliquer et de faire glisser avec un pavé tactile ne fera plus défiler la page.

Nous avons également ajouté la prise en charge de gestes plus complexes sur le pavé tactile, tels que reconnus par la plate-forme depuis l'API 34, y compris les balayages à deux doigts et les pincements. Ces gestes sont automatiquement reconnus par des composants tels que Modifier.scrollable et Modifier.transformable pour un meilleur comportement avec les trackpads.

Ces modifications améliorent le comportement des trackpads dans les composants intégrés, avec la suppression du jeu tactile redondant, un geste de début de glisser-déposer plus intuitif, la sélection par double-clic et triple-clic dans les champs de texte, et les menus contextuels de style ordinateur dans les champs de texte.

Pour tester le comportement du pavé tactile, de nouvelles API de test avec performTrackpadInput, permettent de valider le comportement de vos applications lorsqu'elles sont utilisées avec un pavé tactile. Si vous disposez de détecteurs de gestes personnalisés, validez le comportement sur différents types d'entrées, y compris les écrans tactiles, les souris, les pavés tactiles et les stylets. Assurez-vous que les molettes de souris et les gestes sur pavé tactile sont pris en charge.

beforeAndAfter.webp

Valeurs par défaut de l'hôte de composition (exécution Compose)

Nous avons introduit HostDefaultProvider, LocalHostDefaultProvider, HostDefaultKey et ViewTreeHostDefaultKey pour fournir des services au niveau de l'hôte directement via compose-runtime. Cela évite aux bibliothèques de dépendre de compose-ui pour les recherches, ce qui améliore la compatibilité avec Kotlin Multiplatform. Pour associer ces valeurs à l'arborescence de composition, les auteurs de la bibliothèque peuvent utiliser compositionLocalWithHostDefaultOf pour créer un CompositionLocal qui résout les valeurs par défaut de l'hôte.

Aperçu des wrappers

Les aperçus personnalisés Android Studio sont une nouvelle fonctionnalité qui vous permet de définir précisément comment le contenu d'un aperçu Compose est affiché.

En implémentant l'interface PreviewWrapperProvider et en appliquant la nouvelle annotation @PreviewWrapper, vous pouvez facilement injecter une logique personnalisée, comme l'application d'un Theme spécifique. L'annotation peut être appliquée à une fonction annotée avec @Composable et @Preview ou @MultiPreview, offrant une solution générique et facile à utiliser qui fonctionne avec les fonctionnalités d'aperçu et réduit considérablement le code répétitif.

class ThemeWrapper: PreviewWrapper {
    @Composable
    override fun Wrap(content: @Composable (() -> Unit)) {
        JetsnackTheme {
            content()
        }
    }
}

@PreviewWrapperProvider(ThemeWrapper::class)
@Preview
@Composable
private fun ButtonPreview() {
    // JetsnackTheme in effect
    Button(onClick = {}) {
        Text(text = "Demo")
    }
}

Arrêts et suppressions

  • Comme annoncé dans l'article de blog sur Compose 1.10, nous abandonnons Modifier.onFirstVisible(). Son nom a souvent donné lieu à des idées fausses, en particulier dans les mises en page différées, où il se déclenchait plusieurs fois lors du défilement. Nous vous recommandons de migrer vers Modifier.onVisibilityChanged(), qui permet un suivi manuel plus précis des états de visibilité, adapté aux exigences spécifiques de votre cas d'utilisation.
  • L'option ComposeFoundationFlags.isTextFieldDpadNavigationEnabled a été supprimée, car la navigation au pavé directionnel pour TextFields est désormais toujours activée par défaut. Le nouveau comportement garantit que les événements du pavé directionnel d'une manette de jeu ou d'une télécommande TV déplacent d'abord le curseur dans la direction indiquée. La sélection ne peut passer à un autre élément que lorsque le curseur atteint la fin du texte.

API à venir

Dans la prochaine version 1.12.0 de Compose, compileSdk sera mis à niveau vers compileSdk 37. AGP 9 et toutes les applications et bibliothèques qui dépendent de Compose hériteront de cette exigence. Nous vous recommandons de vous tenir informé des dernières versions publiées, car Compose vise à adopter rapidement les nouveaux compileSdks pour vous donner accès aux dernières fonctionnalités Android. Pour en savoir plus sur la version d'AGP compatible avec les différents niveaux d'API, consultez la documentation

Dans Compose 1.11.0, les API suivantes sont introduites en tant que @Experimental. Nous sommes impatients de connaître votre avis lorsque vous les explorerez dans vos applications. Notez que les @Experimental APIs sont fournis pour une évaluation et des commentaires précoces, et qu'ils peuvent subir des modifications importantes ou être supprimés dans les prochaines versions.

Styles (fonctionnalité expérimentale)

Nous lançons une nouvelle API de base expérimentale pour le style. L'API Style est un nouveau paradigme permettant de personnaliser les éléments visuels des composants, ce qui était traditionnellement effectué avec des modificateurs. Il est conçu pour permettre une personnalisation plus approfondie et plus facile en exposant un ensemble standard de propriétés stylables avec une mise en forme simple basée sur l'état et des transitions animées. Cette nouvelle API nous permet déjà d'obtenir des performances prometteuses. Nous prévoyons d'adopter les styles dans les composants Material une fois que l'API Style sera stabilisée.

Voici un exemple simple de remplacement de l'arrière-plan du style d'état enfoncé :

@Composable
fun LoginButton(modifier: Modifier = Modifier) {
    Button(
        onClick = {
            // Login logic
        },
        modifier = modifier,
        style = {
            background(
                Brush.linearGradient(
                    listOf(lightPurple, lightBlue)
                )
            )
            width(75.dp)
            height(50.dp)
            textAlign(TextAlign.Center)
            externalPadding(16.dp)

            pressed {
                background(
                    Brush.linearGradient(
                        listOf(Color.Magenta, Color.Red)
                    )
                )
            }
        }
    ){
        Text(
            text = "Login",
        )
    }
}
styles.webp

Consultez la documentation et signalez les éventuels bugs ici.

MediaQuery (expérimental)

La nouvelle API mediaQuery offre un moyen déclaratif et performant d'adapter votre UI à son environnement. Il résume la récupération d'informations complexes en conditions simples dans un UiMediaScope, ce qui garantit que la recomposition n'a lieu que lorsque cela est nécessaire.

Grâce à la prise en charge d'un large éventail de signaux environnementaux (des fonctionnalités de l'appareil comme les types de clavier et la précision du pointeur aux états contextuels comme la taille de la fenêtre et la posture), vous pouvez créer des expériences très réactives. Les performances sont intégrées à derivedMediaQuery pour gérer les mises à jour à haute fréquence, tandis que la possibilité de remplacer les portées permet de tester et de prévisualiser facilement les configurations matérielles. Auparavant, pour accéder à certaines propriétés d'appareil (par exemple, pour savoir si un appareil était en mode tablette), vous deviez écrire beaucoup de code standard :

@Composable
fun isTabletopPosture(
    context: Context = LocalContext.current
): Boolean {
    val windowLayoutInfo by
        WindowInfoTracker
            .getOrCreate(context)
            .windowLayoutInfo(context)
            .collectAsStateWithLifecycle(null)

    return windowLayoutInfo.displayFeatures.any { displayFeature ->
        displayFeature is FoldingFeature &&
            displayFeature.state == FoldingFeature.State.HALF_OPENED &&
            displayFeature.orientation == FoldingFeature.Orientation.HORIZONTAL
    }
}

@Composable
fun VideoPlayer() {
    if(isTabletopPosture()) {
        TabletopLayout()
    } else {
        FlatLayout()
    }
}

Désormais, avec UIMediaQuery, vous pouvez ajouter la syntaxe mediaQuery pour interroger les propriétés de l'appareil, par exemple pour savoir si un appareil est en mode tablette :

@OptIn(ExperimentalMediaQueryApi::class)
@Composable
fun VideoPlayer() {
    if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) {
        TabletopLayout()
    } else {
        FlatLayout()
    }
}

Consultez la documentation et signalez les éventuels bugs ici.

Grille (expérimentale)

Grid est une nouvelle API puissante permettant de créer des mises en page bidimensionnelles complexes dans Jetpack Compose. Alors que Row et Column sont parfaits pour les conceptions linéaires, Grid vous offre le contrôle structurel nécessaire pour l'architecture au niveau de l'écran et les composants complexes sans les frais généraux d'une liste déroulante. Grid vous permet de définir votre mise en page à l'aide de pistes, d'espaces et de cellules, en proposant des options de dimensionnement familières telles que Dp, des pourcentages, des tailles de contenu intrinsèques et des unités "Fr" flexibles. 

@OptIn(ExperimentalGridApi::class)
@Composable
fun GridExample() {
    Grid(
        config = {
            repeat(4) { column(0.25f) }
            repeat(2) { row(0.5f) }
            gap(16.dp)
        }
    ) {
        Card1(modifier = Modifier.gridItem(rowSpan = 2)
        Card2(modifier = Modifier.gridItem(colmnSpan = 3)
        Card3(modifier = Modifier.gridItem(columnSpan = 2)
        Card4()
    }
}

Vous pouvez placer des éléments automatiquement ou les étendre explicitement sur plusieurs lignes et colonnes pour plus de précision. Mieux encore, il est très adaptatif : vous pouvez reconfigurer dynamiquement vos pistes et étendues de grille pour répondre aux états de l'appareil, comme le mode Table ou les changements d'orientation, afin de garantir une interface utilisateur esthétique sur tous les facteurs de forme.

Grid.gif

Consultez la documentation et signalez les bugs ici

FlexBox (expérimental)

FlexBox est un conteneur de mise en page conçu pour les interfaces utilisateur adaptatives et hautes performances. Il gère la taille des éléments et la répartition de l'espace en fonction des dimensions du conteneur disponible.  Il gère des tâches complexes telles que l'habillage (wrap) et l'alignement des éléments sur plusieurs axes (justifyContent, alignItems, alignContent). Il permet aux éléments de s'agrandir (grow) ou de se réduire (shrink) pour remplir le conteneur. 

@OptIn(ExperimentalFlexBoxApi::class)
fun FlexBoxWrapping(){
    FlexBox(
        config = {
            wrap(FlexWrap.Wrap)
            gap(8.dp)
        }
    ) {
        RedRoundedBox()
        BlueRoundedBox()
        GreenRoundedBox(modifier = Modifier.width(350.dp).flex { grow(1.0f) })
        OrangeRoundedBox(modifier = Modifier.width(200.dp).flex { grow(0.7f) })
        PinkRoundedBox(modifier = Modifier.width(200.dp).flex { grow(0.3f) })
    }
}
AnimationGif.gif

Consultez la documentation et signalez les éventuels bugs ici.

Nouvelle implémentation de SlotTable (expérimentale)

Nous avons introduit une nouvelle implémentation de SlotTable, qui est désactivée par défaut dans cette version. SlotTable est la structure de données interne que le runtime Compose utilise pour suivre l'état de votre hiérarchie de composition, les invalidations/recompositions, les valeurs mémorisées et toutes les métadonnées de la composition au moment de l'exécution. Cette nouvelle implémentation est conçue pour améliorer les performances, principalement en ce qui concerne les modifications aléatoires.

Pour essayer le nouveau SlotTable, activez ComposeRuntimeFlags.isLinkBufferComposerEnabled

Commencez à coder dès aujourd'hui !

Avec les nombreuses nouvelles API intéressantes de Jetpack Compose, et celles qui sont à venir, c'est le moment idéal pour migrer vers Jetpack Compose.  Comme toujours, nous apprécions vos commentaires et vos demandes de fonctionnalités (en particulier sur les fonctionnalités @Experimental qui sont encore en cours de développement). Veuillez les envoyer ici. Bonne composition !

Écrit par :

Lire la suite