La plate-forme Android est chargée de dessiner l'UI du système, comme la barre d'état et la barre de navigation. Cette UI système s'affiche quelle que soit l'application utilisée par l'utilisateur. WindowInsets
fournit des informations sur l'UI du système pour s'assurer que votre application s'affiche dans la zone appropriée et que votre UI n'est pas masquée par l'UI du système.
Par défaut, l'UI de votre application est limitée à l'interface utilisateur du système, comme la barre d'état et la barre de navigation. Cela garantit que le contenu de votre application n'est pas masqué par les éléments de l'UI du système.
Toutefois, nous recommandons aux applications d'activer l'affichage dans les zones où l'UI du système est également affichée. Cela offrira une expérience utilisateur plus fluide et permettra à votre application de profiter pleinement de l'espace de fenêtre disponible. Cela permet également aux applications de s'animer avec l'UI du système, en particulier lors de l'affichage et du masquage du clavier virtuel.
L'activation de l'affichage dans ces régions et de l'affichage du contenu derrière l'interface utilisateur du système s'appelle une transition bord à bord. Sur cette page, vous découvrirez les différents types d'encarts, comment activer la transition bord à bord et comment utiliser les API d'encart pour animer votre interface utilisateur et éviter de masquer des parties de votre application.
Principes de base des encarts
Lorsqu'une application est bord à bord, vous devez vous assurer que le contenu et les interactions importants ne sont pas masqués par l'UI du système. Par exemple, si un bouton est placé derrière la barre de navigation, l'utilisateur ne pourra peut-être pas cliquer dessus.
La taille de l'UI du système et les informations sur son emplacement sont spécifiées à l'aide d'encarts.
Chaque partie de l'interface utilisateur du système possède un type d'encart correspondant qui décrit sa taille et son emplacement. Par exemple, les encarts de la barre d'état indiquent la taille et la position de la barre d'état, tandis que les encarts de la barre de navigation indiquent la taille et la position de la barre de navigation. Chaque type d'encart comporte quatre dimensions en pixels: haut, gauche, droite et bas. Ces dimensions spécifient la portée de l'UI du système par rapport aux côtés correspondants de la fenêtre de l'application. Pour éviter tout chevauchement avec ce type d'UI du système, l'UI de l'application doit donc être en incrustation.
Ces types d'encarts Android intégrés sont disponibles via WindowInsets
:
Encarts décrivant les barres d'état. Il s'agit des barres supérieures de l'interface utilisateur du système contenant des icônes de notification et d'autres indicateurs. |
|
Des encarts indiquent le moment où ils sont visibles. Si les barres d'état sont actuellement masquées (en raison du passage en mode plein écran immersif), les encarts de la barre d'état principale seront vides, mais ils ne seront pas vides. |
|
Encarts décrivant les barres de navigation. À gauche, à droite ou en bas de l'appareil, ces barres d'interface utilisateur décrivent la barre des tâches ou les icônes de navigation. Ils peuvent changer au moment de l'exécution en fonction de la méthode de navigation préférée de l'utilisateur et de l'interaction avec la barre des tâches. |
|
La barre de navigation s'affiche dans des encarts lorsqu'ils sont visibles. Si les barres de navigation sont actuellement masquées (en raison du passage en mode plein écran immersif), les encarts de la barre de navigation principale seront vides, mais ils ne seront pas vides. |
|
Encart décrivant la décoration de la fenêtre de l'UI du système dans une fenêtre de format libre, comme la barre de titre supérieure. |
|
La barre de sous-titres s'affiche dans des encarts lorsqu'ils sont visibles. Si les barres de sous-titres sont actuellement masquées, les encarts de la barre de sous-titres principale seront vides, mais ils ne le seront pas. |
|
Union des encarts de la barre système, qui incluent les barres d'état, les barres de navigation et la barre de sous-titres. |
|
Des encarts indiquent le moment où ils sont visibles. Si les barres système sont actuellement masquées (en raison du passage en mode plein écran immersif), les encarts de la barre système principale seront vides, mais ils ne le seront pas. |
|
Encarts décrivant la quantité d'espace en bas occupée par le clavier virtuel. |
|
Encarts décrivant l'espace occupé par le clavier virtuel avant l'animation clavier en cours. |
|
Encarts décrivant l'espace occupé par le clavier virtuel après l'animation clavier en cours. |
|
Type d'encarts décrivant des informations plus détaillées sur l'interface utilisateur de navigation, donnant l'espace où les "appuis" seront gérés par le système, et non par l'application. Pour les barres de navigation transparentes avec navigation par gestes, il est possible d'appuyer sur certains éléments de l'application via l'UI de navigation système. |
|
Encarts d'élément sur lesquels l'utilisateur peut appuyer dessus lorsqu'ils sont visibles. Si les éléments tactiles sont actuellement masqués (en raison du passage en mode plein écran immersif), les encarts principaux des éléments tactiles seront vides, mais ils ne seront pas vides. |
|
Encarts représentant le nombre d'encarts où le système interceptera les gestes pour la navigation. Les applications peuvent spécifier manuellement la gestion d'un nombre limité de ces gestes via |
|
Sous-ensemble des gestes système qui seront toujours gérés par le système et qui ne peuvent pas être désactivés via |
|
Encarts représentant la quantité d'espacement nécessaire pour éviter tout chevauchement avec une encoche d'écran (encoche ou petit trou d'épingle). |
|
Encarts représentant les zones incurvées d'un affichage en cascade. Un écran en cascade présente des zones incurvées le long des bords de l'écran, où l'écran commence à s'enrouler sur les côtés de l'appareil. |
Ces types sont résumés en trois types d'encarts "sécurisés" qui garantissent que le contenu n'est pas masqué:
Ces types d'encarts "sécurisés" protègent le contenu de différentes manières, en fonction des encarts de la plate-forme sous-jacente:
- Utilisez
WindowInsets.safeDrawing
pour protéger le contenu qui ne doit pas être affiché sous une UI du système. Il s'agit de l'utilisation la plus courante des encarts, qui permet d'éviter de dessiner du contenu masqué (en partie ou complètement) par l'interface utilisateur du système. - Utilisez
WindowInsets.safeGestures
pour protéger le contenu à l'aide de gestes. Cela évite les conflits entre les gestes système et les gestes de l'application (comme ceux des bottom sheet, des carrousels ou des jeux). - Utilisez
WindowInsets.safeContent
en combinaison deWindowInsets.safeDrawing
etWindowInsets.safeGestures
pour vous assurer que le contenu n'a pas de chevauchement visuel ni de chevauchement de gestes.
Configuration des encarts
Pour permettre à votre application de contrôler entièrement l'emplacement de dessin du contenu, suivez ces étapes de configuration. Sans ces étapes, votre application risque de dessiner des couleurs noires ou unies derrière l'interface utilisateur du système, ou de ne pas s'animer de manière synchrone avec le clavier virtuel.
- Appelez
enableEdgeToEdge()
dansActivity.onCreate
. Cet appel demande que votre application s'affiche derrière l'UI du système. Votre application contrôle ensuite la façon dont ces encarts sont utilisés pour ajuster l'interface utilisateur. Définissez
android:windowSoftInputMode="adjustResize"
dans l'entréeAndroidManifest.xml
de votre activité. Ce paramètre permet à votre application de recevoir la taille de l'IME du logiciel sous forme d'encarts, que vous pouvez utiliser pour remplir et mettre en page le contenu de manière appropriée lorsque l'IME apparaît et disparaît dans votre application.<!-- in your AndroidManifest.xml file: --> <activity android:name=".ui.MainActivity" android:label="@string/app_name" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.MyApplication" android:exported="true">
API Compose
Une fois que votre activité a pris le contrôle de la gestion de tous les encarts, vous pouvez utiliser les API Compose pour vous assurer que le contenu n'est pas masqué et que les éléments interactifs ne se chevauchent pas avec l'UI du système. Ces API synchronisent également la mise en page de votre application avec les modifications des encarts.
Par exemple, il s'agit de la méthode la plus basique 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 la fenêtre safeDrawing
en tant que marge intérieure autour de l'ensemble du contenu de l'application. Bien que cela garantit que les éléments interactifs ne se superposent pas à l'UI du système, cela signifie également qu'aucune application ne s'affichera derrière l'interface utilisateur du système pour obtenir un effet bord à bord. 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 les mises en page qui utilisent ces encarts sont également animées automatiquement à mesure que les valeurs des encarts changent.
Il existe deux façons principales d'utiliser ces types d'encarts pour ajuster vos mises en page modulables: les modificateurs de marge intérieure et les modificateurs de taille d'encart.
Modificateurs de marge intérieure
Modifier.windowInsetsPadding(windowInsets: WindowInsets)
applique les encarts de fenêtre donnés en tant que marge intérieure, agissant 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)
. Il existe des modificateurs analogues pour les autres types d'encarts.
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:
Applique le côté début des windowInsets en tant que largeur (par exemple, |
|
Applique le côté final des windowInsets en tant que largeur (par exemple, |
|
Applique la partie supérieure des windowInsets en hauteur (par exemple, |
|
|
Applique la partie inférieure des windowInsets en hauteur (par exemple, |
Ces modificateurs sont particulièrement utiles pour dimensionner une Spacer
qui occupe l'espace des encarts:
LazyColumn( Modifier.imePadding() ) { // Other content item { Spacer( Modifier.windowInsetsBottomHeight( WindowInsets.systemBars ) ) } }
Consommation d'encarts
Les modificateurs de marge intérieure d'encart (windowInsetsPadding
et les assistants tels que safeDrawingPadding
) consomment automatiquement la partie des encarts appliquée en tant que marge intérieure. En allant plus loin dans 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 ont déjà été utilisés par les modificateurs de marge intérieure d'encart externe. Ils évitent donc d'utiliser la même partie plusieurs fois, ce qui entraînerait trop d'espace supplémentaire.
Les modificateurs de taille d'encart évitent également d'utiliser la même partie d'encarts plusieurs fois si ceux-ci 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, les modificateurs de marge intérieure d'imbrication modifient automatiquement la quantité de marge intérieure appliquée à chaque composable.
En examinant le même exemple LazyColumn
que précédemment, LazyColumn
est redimensionné par le modificateur imePadding
. Dans LazyColumn
, le dernier élément est dimensionné pour 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é, le modificateur imePadding()
n'applique aucune marge intérieure, car l'IME n'a pas de hauteur. Étant donné que le modificateur imePadding()
n'applique aucune marge intérieure, aucun encart n'est utilisé, et la hauteur de Spacer
correspond à celle du bas des barres système.
Lorsque l'IME s'ouvre, il insère une animation pour qu'elle corresponde à la taille de l'IME, et le modificateur imePadding()
commence à appliquer une marge intérieure inférieure pour redimensionner 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 supérieure aux barres système, la hauteur de Spacer
est égale à zéro.
Lorsque l'IME se ferme, les modifications se produisent à l'envers: Spacer
commence à se développer à partir d'une hauteur de zéro une fois que imePadding()
s'applique moins que le bord inférieur des barres système, jusqu'à ce que Spacer
corresponde à la hauteur du côté inférieur des barres système une fois l'IME complètement animé.
Ce comportement est obtenu via la communication entre tous les modificateurs windowInsetsPadding
et peut être influencé de plusieurs autres 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 consommés en tant que marge intérieure. Cette fonctionnalité est utile en association 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é utilisé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 semblable à la version avec un argument WindowInsets
, mais nécessite un PaddingValues
arbitraire à utiliser. Cela est utile pour informer les enfants lorsque la marge intérieure ou l'espacement est fournie par un autre mécanisme que les modificateurs de marge intérieure d'encart, tels qu'une intercalaire Modifier.padding
ordinaire ou à hauteur fixe:
@OptIn(ExperimentalLayoutApi::class) Column(Modifier.padding(16.dp).consumeWindowInsets(PaddingValues(16.dp))) { // content Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime)) }
Si les encarts de fenêtre bruts sont nécessaires sans consommation, utilisez directement les valeurs WindowInsets
ou utilisez WindowInsets.asPaddingValues()
pour renvoyer une PaddingValues
des encarts qui ne sont pas affectés par la consommation.
Toutefois, en raison des mises en garde ci-dessous, il est préférable d'utiliser les modificateurs de marge intérieure des encarts de fenêtre et les modificateurs de taille d'encarts de fenêtre dans la mesure du possible.
Phases des encarts et de Jetpack Compose
Compose utilise les API principales d'AndroidX sous-jacentes pour mettre à jour et animer les encarts, qui utilisent les API de la plate-forme sous-jacente qui gèrent 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 d'encarts 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, ce qui garantit que les valeurs d'encart sont utilisées sur le même frame lors de leur mise à jour.
Animations IME clavier avec WindowInsets
Vous pouvez appliquer Modifier.imeNestedScroll()
à un conteneur à défilement pour ouvrir et fermer automatiquement l'IME lorsque vous faites défiler la page vers le bas du conteneur.
class WindowInsetsExampleActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) WindowCompat.setDecorFitsSystemWindows(window, false) setContent { MaterialTheme { MyScreen() } } } } @OptIn(ExperimentalLayoutApi::class) @Composable fun MyScreen() { Box { LazyColumn( modifier = Modifier .fillMaxSize() // fill the entire window .imePadding() // padding for the bottom for the IME .imeNestedScroll(), // scroll IME at the bottom content = { } ) FloatingActionButton( modifier = Modifier .align(Alignment.BottomEnd) .padding(16.dp) // normal 16dp of padding for FABs .navigationBarsPadding() // padding for navigation bar .imePadding(), // padding for when IME appears onClick = { } ) { Icon(imageVector = Icons.Filled.Add, contentDescription = "Add") } } }
Figure 1 : Animations IME
Prise en charge des encarts avec les composants Material 3
Pour faciliter leur utilisation, de nombreux composables Material 3 intégrés (androidx.compose.material3
) gèrent les encarts selon la façon dont ils sont placés dans votre application selon les spécifications Material.
Gestion des composables à l'intérieur des encarts
Vous trouverez ci-dessous la liste des composants Material qui gèrent automatiquement les encarts.
Barres d'application
TopAppBar
/SmallTopAppBar
/CenterAlignedTopAppBar
/MediumTopAppBar
/LargeTopAppBar
: applique les côtés supérieur et horizontal des barres système en tant que marge intérieure, car elle est utilisée en haut de la fenêtre.BottomAppBar
: applique les côtés bas et horizontal des barres système en tant que marge intérieure.
Conteneurs
ModalDrawerSheet
/DismissibleDrawerSheet
/PermanentDrawerSheet
(contenu dans un panneau de navigation modal): applique des encarts vertical et début au contenu.ModalBottomSheet
: applique les encarts bas.NavigationBar
: applique les encarts bas et horizontal.NavigationRail
: applique les encarts vertical et début.
Scaffold
Par défaut, Scaffold
fournit des encarts en tant que paramètres paddingValues
que vous pouvez utiliser et utiliser.
Scaffold
n'applique pas les encarts au contenu ; cette responsabilité vous appartient.
Par exemple, pour utiliser ces encarts avec un LazyColumn
dans un élément Scaffold
:
Scaffold { innerPadding -> // innerPadding contains inset information for you to use and apply LazyColumn( // consume insets as scaffold doesn't do it by default modifier = Modifier.consumeWindowInsets(innerPadding), contentPadding = innerPadding ) { items(count = 100) { Box( Modifier .fillMaxWidth() .height(50.dp) .background(colors[it % colors.size]) ) } } }
Remplacer les encarts par défaut
Vous pouvez modifier le paramètre windowInsets
transmis au composable pour configurer son comportement. Ce paramètre peut être un autre type d'encart de fenêtre à appliquer à la place, ou désactivé en transmettant une instance vide : WindowInsets(0, 0, 0, 0)
.
Par exemple, pour désactiver la gestion des encarts dans LargeTopAppBar
, définissez le paramètre windowInsets
sur une instance vide:
LargeTopAppBar( windowInsets = WindowInsets(0, 0, 0, 0), title = { Text("Hi") } )
Interopérabilité avec les encarts du système View
Vous devrez peut-être remplacer les encarts par défaut si votre écran contient à la fois des vues et du code Compose dans la même hiérarchie. Dans ce cas, vous devez indiquer clairement lequel doit utiliser les encarts et lequel doit les ignorer.
Par exemple, si votre mise en page de plus haut niveau est une mise en page Android View, vous devez utiliser les encarts dans le système View et les ignorer pour Compose.
Si votre mise en page de plus haut niveau est un composable, vous devez utiliser les encarts dans Compose et remplir les composables AndroidView
en conséquence.
Par défaut, chaque ComposeView
consomme tous les encarts au niveau de consommation WindowInsetsCompat
. Pour modifier ce comportement par défaut, définissez ComposeView.consumeWindowInsets
sur false
.
Ressources
- Now in Android : une application Android entièrement fonctionnelle, développée entièrement avec Kotlin et Jetpack Compose.
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé
- Composants et mises en page Material
- Migrer
CoordinatorLayout
vers Compose - Autres points à prendre en compte