Depuis Android 8.0 (niveau d'API 26), Android permet aux activités de se lancer en mode Picture-in-picture (PIP). Le mode PIP est un type spécial de mode multifenêtre utilisé pour la lecture de vidéos, les appels vidéo et la navigation. Il permet à l'utilisateur d'épingler la fenêtre d'activité existante dans un coin de l'écran tout en naviguant entre les applications ou en parcourant le contenu de l'écran principal.
Le mode PIP exploite les API du mode multifenêtre disponibles dans Android 7.0 pour fournir la fenêtre de superposition vidéo épinglée. Pour ajouter le mode PIP à votre application, vous devez enregistrer les activités compatibles avec le mode PIP, passer votre activité en mode PIP si nécessaire et vous assurer que les éléments d'interface utilisateur sont masqués et que la lecture de la vidéo se poursuit lorsque l'activité est en mode PIP.
La fenêtre PIP apparaît dans la couche supérieure de l'écran, dans un coin choisi par le système.
Le mode PIP est également compatible avec les appareils Android TV OS compatibles exécutant Android 14 (niveau d'API 34) ou une version ultérieure. Bien qu'il existe de nombreuses similitudes, vous devez tenir compte d'autres éléments lorsque vous utilisez le mode PIP sur un téléviseur.
Comment les utilisateurs peuvent interagir avec la fenêtre PIP
Les utilisateurs peuvent faire glisser la fenêtre PIP vers un autre emplacement. Depuis Android 12, les utilisateurs peuvent également :
Appuyer une seule fois sur la fenêtre pour afficher un bouton bascule plein écran, un bouton de fermeture, un bouton de paramètres et des actions personnalisées fournies par votre application (par exemple, des commandes de lecture).
Appuyer deux fois sur la fenêtre pour basculer entre la taille PIP actuelle et la taille PIP maximale ou minimale. Par exemple, appuyer deux fois sur une fenêtre agrandie la réduit, et inversement.
Masquer la fenêtre en la faisant glisser vers le bord gauche ou droit. Pour la réafficher, appuyez sur la partie visible de la fenêtre masquée ou faites-la glisser.
Redimensionner la fenêtre PIP à l'aide du pincement pour zoomer.
Votre application contrôle le moment où l'activité en cours passe en mode PIP. Voici quelques exemples :
Une activité peut passer en mode PIP lorsque l'utilisateur appuie sur le bouton d'accueil ou balaye l'écran vers le haut pour accéder à l'écran d'accueil. C'est ainsi que Google Maps continue d'afficher les itinéraires pendant que l'utilisateur exécute une autre activité en même temps.
Votre application peut passer une vidéo en mode PIP lorsque l'utilisateur revient de la vidéo pour parcourir d'autres contenus.
Votre application peut passer une vidéo en mode PIP pendant qu'un utilisateur regarde la fin d'un épisode de contenu. L'écran principal affiche des informations promotionnelles ou récapitulatives sur l'épisode suivant de la série.
Votre application peut permettre aux utilisateurs de mettre en file d'attente du contenu supplémentaire pendant qu'ils regardent une vidéo. La lecture de la vidéo se poursuit en mode PIP, tandis que l'écran principal affiche une activité de sélection de contenu.
Déclarer la prise en charge du mode PIP
Par défaut, le système ne prend pas automatiquement en charge le mode PIP pour les applications. Si vous souhaitez prendre en charge le mode PIP dans votre application, enregistrez votre activité vidéo dans votre fichier manifeste en définissant android:supportsPictureInPicture sur true. Indiquez également que votre activité gère les modifications de configuration de la mise en page afin qu'elle ne soit pas relancée lorsque des modifications de mise en page se produisent pendant les transitions en mode PIP.
<activity android:name="VideoActivity"
android:supportsPictureInPicture="true"
android:configChanges=
"screenSize|smallestScreenSize|screenLayout|orientation"
...
使用 Jetpack 实现 PiP
使用 Jetpack 画中画库来实现画中画体验,因为它可以简化集成并减少常见的应用内问题。如需查看其使用示例,请参阅我们的平台示例应用。不过,如果您希望使用平台 API 实现 PiP,请参阅以下文档。
Passer votre activité en mode PIP
Depuis Android 12, vous pouvez passer votre activité en mode PIP en définissant
l'indicateur setAutoEnterEnabled sur true. Avec ce paramètre, une activité
passe automatiquement en mode PIP si nécessaire, sans avoir à appeler explicitement
enterPictureInPictureMode() dans onUserLeaveHint. Cela présente l'avantage supplémentaire de fournir des transitions beaucoup plus fluides. Pour en savoir plus, consultez Rendre
les transitions vers le mode PIP plus fluides à partir de la navigation par gestes.
Si vous ciblez Android 11 ou une version antérieure, une activité doit appeler
enterPictureInPictureMode()
pour passer en mode PIP. Par exemple, le code suivant passe une activité en mode PIP lorsque l'utilisateur clique sur un bouton dédié dans l'interface utilisateur de l'application :
Kotlin
override fun onActionClicked(action: Action) { if (action.id.toInt() == R.id.lb_control_picture_in_picture) { activity?.enterPictureInPictureMode() return } }
Java
@Override public void onActionClicked(Action action) { if (action.getId() == R.id.lb_control_picture_in_picture) { getActivity().enterPictureInPictureMode(); return; } ... }
Vous pouvez inclure une logique qui passe une activité en mode PIP au lieu de la mettre en arrière-plan. Par exemple, Google Maps passe en mode PIP si l'utilisateur appuie sur le bouton d'accueil ou sur le bouton "Applications récentes" pendant que l'application est en cours de navigation. Vous pouvez
gérer ce cas en remplaçant
onUserLeaveHint() :
Kotlin
override fun onUserLeaveHint() { if (iWantToBeInPipModeNow()) { enterPictureInPictureMode() } }
Java
@Override public void onUserLeaveHint () { if (iWantToBeInPipModeNow()) { enterPictureInPictureMode(); } }
Recommandation : offrir aux utilisateurs une expérience de transition PIP soignée
Android 12 a apporté des améliorations esthétiques importantes aux transitions animées entre les fenêtres plein écran et PIP. Nous vous recommandons vivement d'implémenter toutes les modifications applicables. Une fois que vous l'aurez fait, ces modifications s'adapteront automatiquement aux grands écrans tels que les appareils pliables et les tablettes sans aucun travail supplémentaire.
Si votre application n'inclut pas les mises à jour applicables, les transitions PIP restent fonctionnelles, mais les animations sont moins soignées. Par exemple, le passage du mode plein écran au mode PIP peut entraîner la disparition de la fenêtre PIP pendant la transition avant qu'elle ne réapparaisse une fois la transition terminée.
Ces modifications impliquent les éléments suivants :
- Rendre les transitions vers le mode PIP plus fluides à partir de la navigation par gestes
- Définir un
sourceRectHintapproprié pour passer en mode PIP et en sortir - Désactiver le redimensionnement fluide pour le contenu non vidéo
Consultez l'exemple Android Kotlin PictureInPicture pour activer une expérience de transition soignée.
Rendre les transitions vers le mode PIP plus fluides à partir de la navigation par gestes
Depuis Android 12, l'indicateur setAutoEnterEnabled offre une animation beaucoup plus
fluide pour passer au contenu vidéo en mode PIP à l'aide de la navigation par gestes, par exemple lorsque vous balayez l'écran vers le haut pour accéder à l'écran d'accueil à partir du mode plein écran.
Pour effectuer cette modification, procédez comme suit :
Utilisez
setAutoEnterEnabledpour créerPictureInPictureParams.Builder:Kotlin
setPictureInPictureParams(PictureInPictureParams.Builder() .setAspectRatio(aspectRatio) .setSourceRectHint(sourceRectHint) .setAutoEnterEnabled(true) .build())
Java
setPictureInPictureParams(new PictureInPictureParams.Builder() .setAspectRatio(aspectRatio) .setSourceRectHint(sourceRectHint) .setAutoEnterEnabled(true) .build());
Appelez
setPictureInPictureParamsavec le à jourPictureInPictureParamsdès le début. L'application n'attend pas le rappelonUserLeaveHint(comme elle l'aurait fait dans Android 11).Par exemple, vous pouvez appeler
setPictureInPictureParamslors de la première lecture et de toute lecture suivante si le format d'image est modifié.Appelez
setAutoEnterEnabled(false), mais uniquement si nécessaire. Par exemple, vous ne souhaitez probablement pas passer en mode PIP si la lecture en cours est en pause.
Définir un sourceRectHint approprié pour passer en mode PIP et en sortir
Depuis l'introduction du mode PIP dans Android 8.0, setSourceRectHint
indique la zone de l'activité visible après la transition en mode
Picture-in-picture, par exemple les limites de la vue vidéo dans un lecteur vidéo.
Avec Android 12, le système utilise sourceRectHint pour implémenter une animation beaucoup plus fluide lors du passage en mode PIP et de la sortie de ce mode.
Pour définir correctement sourceRectHint pour passer en mode PIP et en sortir :
Créez
PictureInPictureParamsen utilisant les limites appropriées commesourceRectHint. Nous vous recommandons également d'associer un écouteur de modification de mise en page au lecteur vidéo :Kotlin
val mOnLayoutChangeListener = OnLayoutChangeListener { v: View?, oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int, newLeft: Int, newTop: Int, newRight: Int, newBottom: Int -> val sourceRectHint = Rect() mYourVideoView.getGlobalVisibleRect(sourceRectHint) val builder = PictureInPictureParams.Builder() .setSourceRectHint(sourceRectHint) setPictureInPictureParams(builder.build()) } mYourVideoView.addOnLayoutChangeListener(mOnLayoutChangeListener)
Java
private final View.OnLayoutChangeListener mOnLayoutChangeListener = (v, oldLeft, oldTop, oldRight, oldBottom, newLeft, newTop, newRight, newBottom) -> { final Rect sourceRectHint = new Rect(); mYourVideoView.getGlobalVisibleRect(sourceRectHint); final PictureInPictureParams.Builder builder = new PictureInPictureParams.Builder() .setSourceRectHint(sourceRectHint); setPictureInPictureParams(builder.build()); }; mYourVideoView.addOnLayoutChangeListener(mOnLayoutChangeListener);
Si nécessaire, mettez à jour le
sourceRectHintavant que le système ne démarre la transition de sortie. Lorsque le système est sur le point de quitter le mode PIP, la hiérarchie des vues de l'activité est disposée selon sa configuration de destination (par exemple, en plein écran). L'application peut associer un écouteur de modification de mise en page à sa vue racine ou à sa vue cible (telle que la vue du lecteur vidéo) pour détecter l'événement et mettre à jour lesourceRectHintavant le début de l'animation.Kotlin
// Listener is called immediately after the user exits PiP but before animating. playerView.addOnLayoutChangeListener { _, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom -> if (left != oldLeft || right != oldRight || top != oldTop || bottom != oldBottom) { // The playerView's bounds changed, update the source hint rect to // reflect its new bounds. val sourceRectHint = Rect() playerView.getGlobalVisibleRect(sourceRectHint) setPictureInPictureParams( PictureInPictureParams.Builder() .setSourceRectHint(sourceRectHint) .build() ) } }
Java
// Listener is called right after the user exits PiP but before animating. playerView.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { if (left != oldLeft || right != oldRight || top != oldTop || bottom != oldBottom) { // The playerView's bounds changed, update the source hint rect to // reflect its new bounds. final Rect sourceRectHint = new Rect(); playerView.getGlobalVisibleRect(sourceRectHint); setPictureInPictureParams( new PictureInPictureParams.Builder() .setSourceRectHint(sourceRectHint) .build()); } });
Désactiver le redimensionnement fluide pour le contenu non vidéo
Android 12 ajoute l'indicateur setSeamlessResizeEnabled, qui fournit une animation de fondu enchaîné beaucoup plus
fluide lors du redimensionnement de contenu non vidéo dans la fenêtre PIP. Auparavant, le redimensionnement de contenu non vidéo dans une fenêtre PIP pouvait créer des artefacts visuels désagréables.
Pour activer le redimensionnement fluide pour le contenu vidéo :
Kotlin
setPictureInPictureParams(PictureInPictureParams.Builder() .setSeamlessResizeEnabled(true) .build())
Java
setPictureInPictureParams(new PictureInPictureParams.Builder() .setSeamlessResizeEnabled(true) .build());
Gérer l'interface utilisateur pendant le mode PIP
Lorsque l'activité passe en mode Picture-in-picture (PIP) ou en sort, le système appelle Activity.onPictureInPictureModeChanged()
ou Fragment.onPictureInPictureModeChanged().
Android 15 introduit des modifications qui garantissent une transition encore plus fluide lors du passage en mode PIP. Cela est utile pour les applications dont les éléments d'interface utilisateur sont superposés à leur interface utilisateur principale, qui passe en mode PIP.
Les développeurs utilisent le onPictureInPictureModeChanged() rappel pour définir une logique qui active ou désactive la visibilité des éléments d'interface utilisateur superposés.
Ce rappel est déclenché lorsque l'animation d'entrée ou de sortie du mode PIP est terminée.
À partir d'Android 15, la PictureInPictureUiState classe inclut un nouvel état.
Avec ce nouvel état d'interface utilisateur, les applications ciblant Android 15 observent l'appel du Activity#onPictureInPictureUiStateChanged()
rappel avec isTransitioningToPip() dès le début de l'animation PIP.
De nombreux éléments d'interface utilisateur ne sont pas pertinents pour l'application lorsqu'elle est en mode PIP, par exemple les vues ou la mise en page qui incluent des informations telles que des suggestions, des vidéos à venir, des notes et des titres. Lorsque l'application passe en mode PIP, utilisez le rappel onPictureInPictureUiStateChanged() pour masquer ces éléments d'interface utilisateur. Lorsque l'application passe en mode plein écran à partir de la fenêtre PIP, utilisez le rappel onPictureInPictureModeChanged() pour afficher ces éléments, comme illustré dans les exemples suivants :
Kotlin
override fun onPictureInPictureUiStateChanged(pipState: PictureInPictureUiState) { if (pipState.isTransitioningToPip()) { // Hide UI elements. } }
Java
@Override public void onPictureInPictureUiStateChanged(PictureInPictureUiState pipState) { if (pipState.isTransitioningToPip()) { // Hide UI elements. } }
Kotlin
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) { if (isInPictureInPictureMode) { // Unhide UI elements. } }
Java
@Override public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) { if (isInPictureInPictureMode) { // Unhide UI elements. } }
Cette activation/désactivation rapide de la visibilité des éléments d'interface utilisateur non pertinents (pour une fenêtre PIP) permet de garantir une animation d'entrée en mode PIP plus fluide et sans scintillement.
Remplacez ces rappels pour redessiner les éléments d'interface utilisateur de l'activité. N'oubliez pas qu'en mode PIP, votre activité s'affiche dans une petite fenêtre. Les utilisateurs ne peuvent pas interagir avec les éléments d'interface utilisateur de votre application lorsque celle-ci est en mode PIP, et les détails des petits éléments d'interface utilisateur peuvent être difficiles à voir. Les activités de lecture vidéo avec une interface utilisateur minimale offrent la meilleure expérience utilisateur.
Si votre application doit fournir des actions personnalisées pour le mode PIP, consultez Ajouter des commandes sur cette page. Supprimez les autres éléments d'interface utilisateur avant que votre activité ne passe en mode PIP et restaurez-les lorsque votre activité redevient plein écran.
Ajouter des commandes
La fenêtre PIP peut afficher des commandes lorsque l'utilisateur ouvre le menu de la fenêtre (en appuyant sur la fenêtre sur un appareil mobile ou en sélectionnant le menu à partir de la télécommande du téléviseur).
Si une application a une session multimédia active, les commandes de lecture, pause, suivant et précédent s'affichent.
Vous pouvez également spécifier explicitement des actions personnalisées en créant
PictureInPictureParams
avec
PictureInPictureParams.Builder.setActions()
avant de passer en mode PIP, et en transmettant les paramètres lorsque vous passez en mode PIP à l'aide de
enterPictureInPictureMode(android.app.PictureInPictureParams)
ou
setPictureInPictureParams(android.app.PictureInPictureParams).
Soyez prudent. Si vous essayez d'ajouter plus de
getMaxNumPictureInPictureActions(),
vous n'obtiendrez que le nombre maximal.
Poursuivre la lecture vidéo en mode PIP
Lorsque votre activité passe en mode PIP, le système la met en pause
et appelle la méthode
onPause() de l'activité. La lecture de la vidéo ne doit pas être mise en pause, mais doit se poursuivre si l'activité est mise en pause lors de la transition vers le mode PIP.
Dans Android 7.0 et versions ultérieures, vous devez mettre en pause et reprendre la lecture vidéo lorsque le
système appelle les méthodes de votre activité
onStop() et
onStart(). Vous n'aurez ainsi pas à vérifier si votre application est en mode PIP dans onPause() et à poursuivre explicitement la lecture.
Si vous n'avez pas défini l'indicateur setAutoEnterEnabled sur true et que vous devez
mettre en pause la lecture dans votre onPause() implémentation, vérifiez le mode PIP en appelant
isInPictureInPictureMode() et gérez la lecture de manière appropriée. Exemple :
Kotlin
override fun onPause() { super.onPause() // If called while in PiP mode, do not pause playback. if (isInPictureInPictureMode) { // Continue playback. } else { // Use existing playback logic for paused activity behavior. } }
Java
@Override public void onPause() { // If called while in PiP mode, do not pause playback. if (isInPictureInPictureMode()) { // Continue playback. ... } else { // Use existing playback logic for paused activity behavior. ... } }
Lorsque votre activité quitte le mode PIP pour revenir en mode plein écran, le système
la reprend et appelle votre
onResume() méthode.
Utiliser une seule activité de lecture pour le mode PIP
Dans votre application, un utilisateur peut sélectionner une nouvelle vidéo lorsqu'il parcourt du contenu sur l'écran principal, tandis qu'une activité de lecture vidéo est en mode PIP. Lisez la nouvelle vidéo dans l'activité de lecture existante en mode plein écran, au lieu de lancer une nouvelle activité qui pourrait dérouter l'utilisateur.
Pour vous assurer qu'une seule activité est utilisée pour les requêtes de lecture vidéo et qu'elle passe en mode PIP ou en sort si nécessaire, définissez android:launchMode de l'activité sur singleTask dans votre fichier manifeste :
<activity android:name="VideoActivity"
...
android:supportsPictureInPicture="true"
android:launchMode="singleTask"
...
Dans votre activité, remplacez
onNewIntent()
et gérez la nouvelle vidéo, en arrêtant toute lecture vidéo existante si nécessaire.
Bonnes pratiques
Le mode PIP peut être désactivé sur les appareils disposant d'une faible quantité de RAM. Avant que votre application n'utilise le mode PIP,
vérifiez qu'il est disponible en appelant
hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE).
Le mode PIP est destiné aux activités qui lisent des vidéos en plein écran. Lorsque vous passez votre activité en mode PIP, évitez d'afficher autre chose que du contenu vidéo. Suivez le moment où votre activité passe en mode PIP et masquez les éléments d'interface utilisateur, comme décrit dans Gérer l'interface utilisateur pendant le mode PIP.
Lorsqu'une activité est en mode PIP, elle ne reçoit pas le focus d'entrée par défaut. Pour
recevoir des événements d'entrée en mode PIP, utilisez
MediaSession.setCallback().
Pour en savoir plus sur l'utilisation de setCallback(), consultez Afficher une carte "En écoute".
Lorsque votre application est en mode PIP, la lecture vidéo dans la fenêtre PIP peut provoquer des interférences audio avec une autre application, telle qu'une application de lecteur de musique ou de recherche vocale. Pour éviter cela, demandez la priorité audio lorsque vous commencez à lire la vidéo et gérez les notifications de modification de la priorité audio, comme décrit dans Gérer la priorité audio. Si vous recevez une notification de perte de la priorité audio en mode PIP, mettez en pause ou arrêtez la lecture vidéo.
Lorsque votre application est sur le point de passer en mode PIP, notez que seule l'activité supérieure passe en mode Picture-in-picture. Dans certaines situations, par exemple sur les appareils en mode multifenêtre, il est possible que l'activité ci-dessous s'affiche et redevienne visible à côté de l'activité PIP. Vous devez gérer ce cas en conséquence, y compris le fait que l'activité ci-dessous reçoit un rappel onResume() ou onPause(). Il est également possible que l'utilisateur interagisse avec l'activité. Par exemple, si vous avez une activité de liste de vidéos affichée et que l'activité de lecture vidéo est en mode PIP, l'utilisateur peut sélectionner une nouvelle vidéo dans la liste et l'activité PIP doit être mise à jour en conséquence.
Exemples de code supplémentaires
Pour télécharger une application exemple écrite en Kotlin, consultez Exemple Android PictureInPicture (Kotlin).