Configurer les encarts de fenêtre

Une fois que votre activité a pris le contrôle de la gestion de tous les encarts, vous pouvez utiliser les API Compose pour vérifier que le contenu n'est pas masqué et que les éléments interactifs ne chevauchent pas l'UI du système. Ces API synchronisent également la mise en page de votre application avec les modifications d'encarts.

Gérer les encarts à l'aide de modificateurs de marge intérieure ou de taille

Par exemple, voici la méthode la plus simple pour appliquer les encarts au contenu de l'ensemble de votre application :

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    enableEdgeToEdge()

    setContent {
        Box(Modifier.safeDrawingPadding()) {
            // the rest of the app
        }
    }
}

Cet extrait applique les encarts de fenêtre safeDrawing en tant que marge intérieure autour de l'intégralité du contenu de l'application. Cela garantit que les éléments interactifs ne chevauchent pas l'UI du système, mais cela signifie également qu'aucune partie de l'application ne sera dessinée derrière l'UI du système pour obtenir un effet plein écran. Pour exploiter pleinement l'intégralité de la fenêtre, vous devez ajuster l'emplacement des encarts écran par écran ou composant par composant.

Tous ces types d'encarts sont animés automatiquement avec des animations IME rétroportées vers l'API 21. Par extension, toutes vos mises en page utilisant ces encarts sont également animées automatiquement lorsque les valeurs des encarts changent.

Il existe trois façons de gérer les encarts pour ajuster vos mises en page composables :

Modificateurs de marge intérieure

Modifier.windowInsetsPadding(windowInsets: WindowInsets) applique les encarts de fenêtre donnés en tant que marge intérieure, comme le ferait Modifier.padding. Par exemple, Modifier.windowInsetsPadding(WindowInsets.safeDrawing) applique les encarts de dessin sécurisés en tant que marge intérieure sur les quatre côtés.

Il existe également plusieurs méthodes utilitaires intégrées pour les types d'encarts les plus courants. Modifier.safeDrawingPadding() est l'une de ces méthodes, équivalente à Modifier.windowInsetsPadding(WindowInsets.safeDrawing). Le tableau suivant liste les modificateurs de marge intérieure intégrés et le type WindowInsets appliqué par chacun d'eux :

Modifier.safeDrawingPadding()

WindowInsets.safeDrawing

Modifier.safeGesturesPadding()

WindowInsets.safeGestures

Modifier.safeContentPadding()

WindowInsets.safeContent

Modifier.statusBarsPadding()

WindowInsets.statusBars

Modifier.navigationBarsPadding()

WindowInsets.navigationBars

Modifier.captionBarPadding()

WindowInsets.captionBar

Modifier.systemBarsPadding()

WindowInsets.systemBars

Modifier.imePadding()

WindowInsets.ime

Modifier.systemGesturesPadding()

WindowInsets.systemGestures

Modifier.mandatorySystemGesturesPadding()

WindowInsets.mandatorySystemGestures

Modifier.displayCutoutPadding()

WindowInsets.displayCutout

Modifier.waterfallPadding()

WindowInsets.waterfall

Pour savoir ce que couvre chaque type d'encart, consultez À propos des encarts de fenêtre.

Modificateurs de taille d'encart

Les modificateurs suivants appliquent une quantité d'encarts de fenêtre en définissant la taille du composant sur celle des encarts :

Modifier.windowInsetsStartWidth(windowInsets: WindowInsets)

Applique le côté de début de windowInsets comme largeur (comme Modifier.width)

Modifier.windowInsetsEndWidth(windowInsets: WindowInsets)

Applique le côté de fin de windowInsets comme largeur (comme Modifier.width)

Modifier.windowInsetsTopHeight(windowInsets: WindowInsets)

Applique le côté supérieur de windowInsets comme hauteur (comme Modifier.height)

Modifier.windowInsetsBottomHeight(windowInsets: WindowInsets)

Applique le côté inférieur de windowInsets comme hauteur (comme Modifier.height)

Ces modificateurs sont particulièrement utiles pour dimensionner un Spacer qui occupe l'espace des encarts :

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

Consommation de l'encart

Les modificateurs de marge intérieure (windowInsetsPadding et les assistants tels que safeDrawingPadding) consomment automatiquement la partie des encarts appliqués en tant que marge intérieure. En approfondissant l'arborescence de composition, les modificateurs de marge intérieure d'encart imbriqués et les modificateurs de taille d'encart savent qu'une partie des encarts a déjà été utilisée par les modificateurs de marge intérieure d'encart externes. Ils évitent d'utiliser la même partie des encarts plusieurs fois, ce qui entraînerait un espace supplémentaire trop important.

Les modificateurs de taille d'encart évitent également d'utiliser plusieurs fois la même partie d'encart si les encarts ont déjà été utilisés. Toutefois, comme ils modifient directement leur taille, ils ne consomment pas eux-mêmes les encarts.

Par conséquent, l'imbrication des modificateurs de marge intérieure modifie automatiquement la quantité de marge intérieure appliquée à chaque composable.

En reprenant le même exemple LazyColumn que précédemment, l'élément LazyColumn est redimensionné par le modificateur imePadding. Dans LazyColumn, le dernier élément est dimensionné de manière à correspondre à la hauteur du bas des barres système :

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

Lorsque l'IME est fermé, imePadding() n'applique aucune marge intérieure. Par conséquent, aucun encart n'est consommé et la hauteur de Spacer correspond aux barres système inférieures.

Lorsque l'IME s'ouvre, les encarts de l'IME s'animent pour correspondre à la taille de l'IME, et le modificateur imePadding() commence à appliquer une marge intérieure inférieure pour redimensionner le LazyColumn à l'ouverture de l'IME. Lorsque le modificateur imePadding() commence à appliquer une marge intérieure inférieure, il commence également à consommer cette quantité d'encarts. Par conséquent, la hauteur de Spacer commence à diminuer, car une partie de l'espacement des barres système a déjà été appliquée par le modificateur imePadding(). Une fois que le modificateur imePadding() applique une marge intérieure inférieure plus grande que les barres système, la hauteur de Spacer est de zéro.

Lorsque l'IME se ferme, les modifications se produisent dans l'ordre inverse : Spacer s'étend à partir d'une hauteur nulle, car imePadding() applique moins que les barres système inférieures. Enfin, la hauteur de Spacer correspond aux barres système une fois que l'IME est entièrement animé.

Figure 2. Colonne Lazy bord à bord avec TextField.

Ce comportement est obtenu grâce à la communication entre tous les modificateurs windowInsetsPadding et peut être influencé de différentes manières.

Modifier.consumeWindowInsets(insets: WindowInsets) utilise également les encarts de la même manière que Modifier.windowInsetsPadding, mais il n'applique pas les encarts utilisés comme marge intérieure. Cela est utile en combinaison avec les modificateurs de taille d'encart, pour indiquer aux frères et sœurs qu'une certaine quantité d'encarts a déjà été consommée :

Column(Modifier.verticalScroll(rememberScrollState())) {
    Spacer(Modifier.windowInsetsTopHeight(WindowInsets.systemBars))

    Column(
        Modifier.consumeWindowInsets(
            WindowInsets.systemBars.only(WindowInsetsSides.Vertical)
        )
    ) {
        // content
        Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
    }

    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.systemBars))
}

Modifier.consumeWindowInsets(paddingValues: PaddingValues) se comporte de manière très similaire à la version avec un argument WindowInsets, mais utilise un PaddingValues arbitraire à consommer. Cela permet d'informer les enfants lorsque la marge intérieure ou l'espacement sont fournis par un autre mécanisme que les modificateurs de marge intérieure, comme un Modifier.padding ordinaire ou des espaces de hauteur fixe :

Column(Modifier.padding(16.dp).consumeWindowInsets(PaddingValues(16.dp))) {
    // content
    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
}

Si vous avez besoin des encarts de fenêtre bruts sans consommation, utilisez directement les valeurs WindowInsets ou utilisez WindowInsets.asPaddingValues() pour renvoyer un PaddingValues des encarts qui ne sont pas affectés par la consommation. Toutefois, en raison des mises en garde suivantes, privilégiez l'utilisation des modificateurs de marge intérieure et de taille des encarts de fenêtre dans la mesure du possible.

Insets et phases de Jetpack Compose

Compose utilise les API de base AndroidX sous-jacentes pour mettre à jour et animer les encarts, qui utilisent les API de plate-forme sous-jacentes gérant les encarts. En raison de ce comportement de la plate-forme, les encarts ont une relation particulière avec les phases de Jetpack Compose.

La valeur des encarts est mise à jour après la phase de composition, mais avant la phase de mise en page. Cela signifie que la lecture de la valeur des encarts dans la composition utilise généralement une valeur des encarts qui est en retard d'une image. Les modificateurs intégrés décrits sur cette page sont conçus pour retarder l'utilisation des valeurs des encarts jusqu'à la phase de mise en page. Cela garantit que les valeurs des encarts sont utilisées sur le même frame que celui où elles sont mises à jour.