La plate-forme Android est chargée de dessiner l'interface utilisateur 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 bonne zone et que votre UI n'est pas masquée par l'UI du système.
Par défaut, l'interface utilisateur de votre application ne peut être affichée que dans 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 des éléments d'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 se traduit par une expérience utilisateur plus fluide et permet à votre application d'exploiter pleinement l'espace disponible dans la fenêtre. Cela permet également aux applications de s'animer avec l'UI du système, en particulier lorsque le clavier virtuel est affiché et masqué.
L'activation de l'affichage dans ces régions et l'affichage du contenu derrière l'interface utilisateur du système s'appelle l'affichage de bord à bord. Sur cette page, vous découvrirez les différents types d'encarts, comment activer l'affichage bord à bord et comment utiliser les API d'encart pour animer votre interface utilisateur et éviter d'obscurcir certaines parties de votre application.
Fondamentaux en encart
Lorsqu'une application s'affiche de 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 risque de ne pas pouvoir cliquer dessus.
La taille de l'interface utilisateur du système et les informations sur son emplacement sont spécifiés via des encarts.
Chaque partie de l'UI 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 sa taille et sa position. Chaque type d'encart est constitué de quatre dimensions en pixels: haut, gauche, droite et bas. Ces dimensions indiquent la distance dans laquelle l'interface utilisateur du système s'étend 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 être placée en encart par cette quantité.
Ces types d'encarts Android intégrés sont disponibles via WindowInsets
:
Encarts décrivant les barres d'état. Les barres supérieures de l'interface utilisateur du système contiennent les icônes de notification et d'autres indicateurs. |
|
La barre d'état apparaît en médaillons lorsque ces éléments sont visibles. Si les barres d'état sont actuellement masquées (en raison du passage en mode immersif en plein écran), les encarts de la barre d'état principale seront vides, mais ils ne le seront pas. |
|
Encarts décrivant les barres de navigation. Il s'agit des barres d'UI du système à gauche, à droite ou en bas de l'appareil. Elles décrivent la barre des tâches ou les icônes de navigation. Ceux-ci 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'insère dans des encarts pour indiquer quand ils sont visibles. Si les barres de navigation sont actuellement masquées (en raison du passage en mode immersif en plein écran), les encarts de la barre de navigation principale seront vides, mais ils ne le seront pas. |
|
Encart décrivant la décoration de la fenêtre de l'UI du système s'il se trouve dans une fenêtre de forme libre, comme la barre de titre supérieure. |
|
La barre de sous-titres est encadrée pour indiquer quand 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 le seront. |
|
L'union des encarts de la barre système, qui comprend les barres d'état, les barres de navigation et la barre de sous-titres. |
|
La barre système s'affiche en médaillons pour indiquer qu'ils sont visibles. Si les barres système sont actuellement masquées (en raison du passage en mode immersif en plein écran), les encarts de la barre système principale seront vides, mais ils ne le seront pas. |
|
Encarts décrivant l'espace en bas que le clavier virtuel occupe. |
|
Encarts décrivant l'espace occupé par le clavier virtuel avant l'animation actuelle du clavier. |
|
Encarts décrivant l'espace que le clavier virtuel occupera après l'animation actuelle du clavier. |
|
Type d'encarts décrivant des informations plus détaillées sur l'interface utilisateur de navigation, offrant la quantité d'espace où les appuis seront gérés par le système, et non par l'application. Pour les barres de navigation transparentes avec la navigation par gestes, il est possible d'appuyer sur certains éléments de l'application via l'UI de navigation du système. |
|
Encarts d'élément tactiles qui s'affichent lorsque ceux-ci sont visibles. Si les éléments tactiles sont actuellement masqués (en raison du passage en mode immersif en plein écran), les encarts principaux des éléments tactiles seront vides, mais ils ne le seront pas. |
|
Encarts représentant le nombre d'encarts où le système intercepte les gestes de navigation. Les applications peuvent spécifier manuellement la gestion d'un nombre limité de ces gestes via |
|
Sous-ensemble de gestes système qui seront toujours gérés par le système et qui ne peuvent pas être désactivés via |
|
Les encarts représentant l'espacement nécessaire pour éviter de chevaucher une encoche (encoche ou trou d'épingle). |
|
Encarts représentant les zones incurvées d'une cascade. Un écran en cascade présente des zones incurvées le long des bords de l'écran, là où celui-ci commence à s'enrouler sur les côtés de l'appareil. |
Ces types d'encarts sont résumés par 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 dessiné sous une interface utilisateur système. Il s'agit de l'utilisation la plus courante des encarts, qui permet d'éviter de dessiner du contenu masqué (partiellement ou complètement) par l'interface utilisateur du système. - Utilisez
WindowInsets.safeGestures
pour protéger des contenus à l'aide de gestes. Cela permet d'éviter les conflits entre les gestes système et les gestes d'application (tels que ceux des bottom sheets, des carrousels ou des jeux). - Utilisez
WindowInsets.safeContent
en combinaison deWindowInsets.safeDrawing
etWindowInsets.safeGestures
pour vous assurer que le contenu ne présente aucun chevauchement visuel ni geste.
Configuration des encarts
Pour donner à votre application un contrôle total sur l'emplacement où elle dessine le contenu, suivez ces étapes de configuration. Sans ces étapes, votre application risque d'afficher 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ôlera alors la façon dont ces encarts sont utilisés pour ajuster l'UI. 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 obscurci 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 apportées aux 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 tout le 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'UI du système pour obtenir un effet de bord à bord. Pour exploiter pleinement 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 automatiquement animées à mesure que les valeurs d'encart changent.
Il existe deux façons principales d'utiliser ces types d'encarts pour ajuster vos mises en page composables: 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, comme le ferait Modifier.padding
.
Par exemple, Modifier.windowInsetsPadding(WindowInsets.safeDrawing)
applique les encarts de dessin sécurisés en tant que marges intérieures 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, qui équivaut à 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 certaine quantité d'encarts de fenêtre en définissant la taille du composant sur la taille des encarts:
Applique le côté de début de windowInsets en tant que largeur (comme |
|
Applique la fin des encarts windowInsets en tant que largeur (comme |
|
Applique la partie supérieure des encarts windowInsets en tant que hauteur (comme |
|
|
Applique la partie inférieure des encarts windowInsets en tant que hauteur (comme |
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 (windowInsetsPadding
et les assistants tels que safeDrawingPadding
) consomment automatiquement la partie des encarts qui sont appliquées en tant que marge intérieure. En explorant plus en profondeur 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. Par conséquent, évitez d'utiliser la même partie des encarts plusieurs fois, ce qui entraînerait un espace trop important.
Les modificateurs de taille d'encart évitent également d'utiliser la même partie des 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 d'encarts.
Par conséquent, les modificateurs de marge intérieure imbriqués modifient automatiquement la quantité de marge intérieure appliquée à chaque composable.
Si nous reprenons le même exemple de LazyColumn
qu'auparavant, LazyColumn
est redimensionné par le modificateur imePadding
. Dans LazyColumn
, le dernier élément correspond à 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 à la taille du côté inférieur des barres système.
Lorsque l'IME s'ouvre, les encarts s'animent pour correspondre à la taille de l'IME, et le modificateur imePadding()
commence à appliquer une marge 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 l'espacement des barres système a déjà été appliqué 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'inverse: Spacer
commence à se développer à partir d'une hauteur de zéro une fois que imePadding()
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 que l'IME est complètement animé.
Ce comportement est obtenu via 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
, à la différence qu'il n'applique pas les encarts consommés comme marge intérieure. Combiné aux modificateurs de taille d'encart, cette méthode est utile pour indiquer aux frères 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 sont fournis par un autre mécanisme que les modificateurs de marge intérieure d'encart, tels qu'un élément Modifier.padding
ordinaire ou des espaces de séparation à 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 être consommés, 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 ci-dessous, il est préférable d'utiliser les modificateurs de marge intérieure et d'encart de fenêtre dans la mesure du possible.
Phases d'encarts et de Jetpack Compose
Compose utilise les API principales AndroidX sous-jacentes pour mettre à jour et animer les encarts, qui utilisent les API de plate-forme sous-jacentes 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 de 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 la même image lors de leur mise à jour.
Animations IME du 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 jusqu'en 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
Compatibilité des encarts avec les composants Material 3
Pour faciliter l'utilisation, de nombreux composables Material 3 intégrés (androidx.compose.material3
) gèrent eux-mêmes les encarts, en fonction de la manière dont ils sont placés dans votre application conformément aux spécifications de Material.
Gestion des composables de l'encart
Vous trouverez ci-dessous une liste des composants Material qui gèrent automatiquement les encarts.
Barres d'application
TopAppBar
/SmallTopAppBar
/CenterAlignedTopAppBar
/MediumTopAppBar
/LargeTopAppBar
: applique les côtés supérieurs et horizontal des barres système en tant que marge intérieure, car celle-ci 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 inférieurs et horizontaux.NavigationRail
: applique les encarts vertical et start.
Scaffold
Par défaut, Scaffold
fournit des encarts en tant que paramètre paddingValues
que vous pouvez consommer et utiliser.
Scaffold
n'applique pas les encarts au contenu. Cette responsabilité vous incombe.
Par exemple, pour utiliser ces encarts avec un LazyColumn
dans un 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 correspondre à un autre type d'encart de fenêtre à appliquer à la place, ou être désactivé en transmettant une instance vide : WindowInsets(0, 0, 0, 0)
.
Par exemple, pour désactiver la gestion des encarts sur 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 de vues
Vous devrez peut-être remplacer les encarts par défaut lorsque le code des vues et du code Compose se trouvent dans la même hiérarchie sur votre écran. Dans ce cas, vous devez indiquer explicitement lequel utiliser les encarts et lequel les ignorer.
Par exemple, si votre mise en page externe est une mise en page Android View, vous devez utiliser les encarts dans le système de vues et les ignorer pour Compose.
Si votre mise en page externe 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, conçue 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