Le fenêtrage du bureau permet aux utilisateurs d'exécuter plusieurs applications simultanément dans des fenêtres d'application redimensionnables pour une expérience polyvalente semblable à celle d'un ordinateur de bureau.
La figure 1 illustre l'organisation de l'écran lorsque le fenêtrage du bureau est activé. Points à noter :
- Les utilisateurs peuvent exécuter plusieurs applications côte à côte simultanément.
- La barre des tâches est située en bas de l'écran et affiche les applications en cours d'exécution. Les utilisateurs peuvent épingler des applications pour y accéder rapidement.
- Une nouvelle barre d'en-tête personnalisable décore le haut de chaque fenêtre avec des commandes telles que "Réduire" et "Agrandir".
Par défaut, les applications s'ouvrent en plein écran sur les tablettes Android. Pour lancer une application en mode fenêtrage du bureau, appuyez de manière prolongée sur la poignée de la fenêtre en haut de l'écran, puis faites-la glisser dans l'interface utilisateur, comme illustré à la figure 2.
Lorsqu'une application est ouverte en mode fenêtrage du bureau, les autres applications s'ouvrent également dans des fenêtres de bureau.
Les utilisateurs peuvent également activer le fenêtrage du bureau à partir du menu qui s'affiche sous la poignée de la fenêtre lorsque vous appuyez ou cliquez dessus, ou à l'aide du raccourci clavier Meta key (Windows, Command, or Search) + Ctrl + Down.
Pour quitter le fenêtrage du bureau, les utilisateurs peuvent fermer toutes les fenêtres actives ou saisir la poignée de la fenêtre en haut d'une fenêtre de bureau et faire glisser l'application en haut de l'écran. Le raccourci clavier Meta + H permet également de quitter le fenêtrage du bureau et d’exécuter à nouveau les applications en plein écran.
Pour revenir au fenêtrage du bureau, appuyez ou cliquez sur la vignette "Espace de bureau" dans l'écran "Récents".
Optimiser la mise en page de votre application pour un environnement semblable à celui d'un ordinateur de bureau
La conception pour une expérience sur ordinateur de bureau peut être très différente de la conception mobile en raison de l'espace d'écran plus important, de la précision de la saisie au clavier et à la souris, et de l'attente d'une productivité élevée.
Jetpack WindowManager fournit une API qui aide les développeurs à décider quand afficher une interface utilisateur de bureau, qui présente généralement une densité d'informations plus élevée, des schémas de navigation différents et des interactions optimisées avec la souris.
lifecycleScope.launch(Dispatchers.Main) { lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { windowInfoTracker.windowEngagementInfo(this@DesktopWindowingActivity) .collect { windowEngagementInfo -> if(windowEngagementInfo.hasEngagementMode(WindowEngagementInfo.EngagementMode.PRECISE_POINTER)){ showDesktopOptimizedUI() }else { showTouchOptimizedUI() } } } }
Pour en savoir plus, consultez la section Concevoir pour un ordinateur de bureau.
Mode de redimensionnement et de compatibilité
En mode fenêtrage du bureau, les applications dont l'orientation est verrouillée sont librement redimensionnables. Cela signifie que même si une activité est verrouillée en mode Portrait, les utilisateurs peuvent toujours redimensionner l'application dans une fenêtre en mode Paysage.
L'interface utilisateur des applications déclarées comme non redimensionnables (c'est-à-dire resizeableActivity = false) est mise à l'échelle
tout en conservant les mêmes proportions.
Les applications d'appareil photo qui verrouillent l'orientation ou sont déclarées comme non redimensionnables bénéficient d'un traitement spécial pour leur viseur : la fenêtre est entièrement redimensionnable, mais le viseur conserve les mêmes proportions. En supposant que les applications s'exécutent toujours en mode Portrait ou Paysage, elles codent en dur ou font des hypothèses qui entraînent des erreurs de calcul de l'orientation ou des proportions de l'aperçu ou de l'image capturée, ce qui donne des images étirées, latérales ou à l'envers.
En attendant que les applications soient prêtes à implémenter des viseurs d'appareil photo entièrement adaptatifs, le traitement spécial offre une expérience utilisateur plus basique qui atténue les effets que de mauvaises hypothèses peuvent entraîner.
Pour en savoir plus sur le mode de compatibilité des applications d'appareil photo, consultez la section Mode de compatibilité avec les appareils.
Marges d'en-tête personnalisables
Toutes les applications exécutées en mode fenêtrage du bureau comportent une barre d'en-tête, même en mode immersif. Vous pouvez personnaliser cette barre pour éviter que le contenu de votre application ne soit masqué et pour dessiner des éléments d'interface utilisateur personnalisés directement dans l'espace d'en-tête.
Implémentation
Pour dessiner du contenu personnalisé dans la barre d'en-tête, vous devez d'abord rendre transparent l'arrière-plan de la barre d'en-tête. Pour cela, utilisez l'
APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND avec l'
WindowInsetsController.
window.insetsController?.setSystemBarsAppearance( WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND, WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND )
Une fois la barre d'en-tête transparente, vous pouvez styliser la zone d'en-tête pour qu'elle corresponde à la conception de votre application. Utilisez WindowInsets.isCaptionBarVisible pour détecter si la barre est
présente et appliquer la hauteur ou la marge intérieure appropriée à votre mise en page.
@OptIn(ExperimentalLayoutApi::class) @Composable fun CaptionBar() { if (WindowInsets.isCaptionBarVisible) { Row( modifier = Modifier .windowInsetsTopHeight(WindowInsets.captionBar) .fillMaxWidth() .background(if (isSystemInDarkTheme()) Color.White else Color.Black), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { Text( text = "Caption Bar Title", style = MaterialTheme.typography.titleMedium, modifier = Modifier.padding(4.dp) ) } } }
setSystemBarsAppearance(appearance,mask): configure le style visuel des barres système. Le premier paramètre définit les options d'apparence cibles, tandis que le second sert de masque pour contrôler les options spécifiques qui sont modifiées.windowInsetsTopHeight(): définit automatiquement la hauteur de votre composable pour qu'elle corresponde à la barre d'en-tête du système, ce qui permet à votre arrière-plan personnalisé de remplir la zone de légende sans coder en dur les valeurs de pixels.WindowInsets.captionBar: fournit les dimensions des commandes de fenêtrage du bureau (Fermer, Agrandir, etc.), ce qui permet à votre interface utilisateur de se mettre à l'échelle ou de se masquer automatiquement lorsque vous activez ou désactivez le fenêtrage du bureau.
Pour en savoir plus, consultez la section À propos des marges de fenêtre. En plus d'un titre, vous pouvez afficher d'autres éléments d'interface utilisateur dans la barre de légende, tels que des onglets (comme dans Google Chrome), des barres de recherche ou des avatars de profil.
Interface utilisateur
Pour éviter de chevaucher votre interface utilisateur avec les boutons système, Android 15 fournit la
WindowInsets#getBoundingRects() méthode. La méthode renvoie une liste d'objets représentant les zones occupées par les éléments système.Rect Tout espace restant dans la barre de légende est une zone de sécurité où vous pouvez placer du contenu personnalisé en toute sécurité.
Basculez l'apparence des éléments de légende du système pour les thèmes clair et sombre à l'aide de
APPEARANCE_LIGHT_CAPTION_BARS. Accédez aux marges à l'aide de
WindowInsets.Companion.captionBar() dans Compose ou
WindowInsets.Type.captionBar() dans Views.
Pour en savoir plus, consultez la section À propos des marges de fenêtre.
Compatibilité avec le multitâche et les instances multiples
Le multitâche est au cœur du fenêtrage du bureau, et autoriser plusieurs instances de votre application peut augmenter considérablement la productivité des utilisateurs.
À partir d'Android 15, vous pouvez utiliser
PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI. En définissant cette propriété dans votre AndroidManifest.xml, vous spécifiez que l'interface utilisateur du système doit fournir des options (comme un bouton "Nouvelle fenêtre") pour que l'application soit lancée dans plusieurs instances.
<application>
<property
android:name="android.window.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI"
android:value="true" />
</application>
Remarque : En mode fenêtrage du bureau et dans d'autres environnements multifenêtre, les nouvelles tâches s'ouvrent dans une nouvelle fenêtre. Vérifiez donc le parcours utilisateur chaque fois que votre application démarre plusieurs tâches.
Gérer les instances d'application avec des gestes de glissement
En mode multifenêtre, les utilisateurs peuvent démarrer une nouvelle instance d'application en faisant glisser un élément d'interface utilisateur (tel qu'un onglet ou un document) hors de la fenêtre de l'application. Les utilisateurs peuvent également déplacer des éléments entre différentes instances de la même application.
Transférer des données par glisser-déposer
Pour configurer un composable en tant que source de glissement pour le glisser-déposer multi-instance
ce qui permet aux utilisateurs de faire glisser du contenu vers une autre instance de votre application ou de créer une
nouvelle instance en déposant du contenu dans une zone vide de l'écran, utilisez le
dragAndDropSource modificateur. Dans son lambda, renvoyez
DragAndDropTransferData, en transmettant le ClipData qui contient les données à
transférer, ainsi que des options pour configurer le comportement multi-instance.
Android 15 introduit deux options clés pour le fenêtrage de style bureau et les interactions multi-instance :
DRAG_FLAG_GLOBAL_SAME_APPLICATION: indique qu'une opération de glissement peut traverser les limites de la fenêtre (pour plusieurs instances de la même application). LorsquestartDragAndDrop()est appelé avec cette option définie, seules les fenêtres visibles appartenant à la même application peuvent participer à l'opération de glissement et recevoir le contenu déplacé.
Modifier.dragAndDropSource { _ -> DragAndDropTransferData( clipData = ClipData.newPlainText("label", "Your data"), flags = View.DRAG_FLAG_GLOBAL_SAME_APPLICATION ) }
DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG: permet aux utilisateurs de démarrer une nouvelle instance de votre application en déposant le contenu déplacé dans une zone vide de l'écran, si aucune autre fenêtre ne gère le dépôt.- Lorsque vous utilisez cette option, vous devez fournir un
IntentSenderà l'aide deClipData.Item.Builder#setIntentSender(), que le système utilise pour lancer la nouvelle activité si un dépôt non géré se produit.
- Lorsque vous utilisez cette option, vous devez fournir un
Modifier.dragAndDropSource { _ -> val intent = Intent.makeMainActivity(activity.componentName).apply { putExtra("EXTRA_ITEM_ID", itemId) flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK or Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT } val pendingIntent = PendingIntent.getActivity( activity, 0, intent, PendingIntent.FLAG_IMMUTABLE ) val data = ClipData( "Item $itemId", arrayOf(ClipDescription.MIMETYPE_TEXT_INTENT), ClipData.Item.Builder().setIntentSender(pendingIntent.intentSender).build() ) DragAndDropTransferData( clipData = data, flags = View.DRAG_FLAG_GLOBAL_SAME_APPLICATION or View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG, ) }
Recevoir les données transférées
Pour accepter les données d'une autre instance, utilisez le dragAndDropTarget modificateur.
Vous devez demander explicitement des autorisations si les données proviennent d'une autre instance ou application.
Modifier.dragAndDropTarget( shouldStartDragAndDrop = { event -> event.toAndroidDragEvent().clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN) }, target = object : DragAndDropTarget { override fun onDrop(event: DragAndDropEvent): Boolean { requestDragAndDropPermissions(activity, event.toAndroidDragEvent()) val clipData = event.toAndroidDragEvent().clipData val item = clipData?.getItemAt(0)?.text if (item != null) { // Process the dropped text item here } return item != null } } )
Étapes clés :
- Filtrer : utilisez
shouldStartDragAndDroppour vérifier si les données entrantes (type MIME) sont compatibles. - Autorisations : appelez
requestDragAndDropPermissions(event)pour accéder aux données. - Gérer : extrayez les données dans le
onDroprappel.
Optimisations supplémentaires
Personnalisez les lancements d'applications et passez des applications du fenêtrage du bureau au plein écran.
Spécifier la taille et la position par défaut
Toutes les applications, même si elles sont redimensionnables, n'ont pas besoin d'une grande fenêtre pour offrir une valeur ajoutée à l'utilisateur. Vous
pouvez utiliser la ActivityOptions#setLaunchBounds() méthode pour spécifier une taille et une position par défaut
lors du lancement d'une activité.
Passer en plein écran depuis l'espace de bureau
Les applications peuvent passer en plein écran en appelant Activity#requestFullScreenMode(). La méthode affiche l'application en plein écran directement à partir du fenêtrage du bureau.