Media3 fournit un PlayerView par défaut qui propose des options de personnalisation.
Remplacer les drawables
PlayerView utilise PlayerControlView pour afficher les commandes de lecture et la barre de progression. Les drawables utilisés par PlayerControlView peuvent être remplacés par des drawables portant les mêmes noms définis dans votre application. Consultez la documentation PlayerControlView pour obtenir la liste des drawables de contrôle pouvant être remplacés.
Pour toute personnalisation supplémentaire, les développeurs d'applications doivent implémenter leurs propres composants d'interface utilisateur. Cependant, voici quelques bonnes pratiques qui peuvent vous aider à démarrer.
Bonnes pratiques
Lorsque vous implémentez une UI multimédia qui se connecte à un Player Media3 (par exemple, ExoPlayer, MediaController ou une implémentation Player personnalisée), nous vous conseillons de suivre ces bonnes pratiques pour une expérience utilisateur optimale.
Bouton de lecture/pause
Le bouton de lecture et de mise en pause ne correspond pas directement à un seul état du lecteur. Par exemple, un utilisateur doit pouvoir redémarrer la lecture après qu'elle s'est terminée ou a échoué, même si le lecteur n'est pas en pause.
Pour simplifier l'implémentation, Media3 fournit des méthodes utilitaires permettant de décider quel bouton afficher (Util.shouldShowPlayButton) et de gérer les pressions sur les boutons (Util.handlePlayPauseButtonAction) :
Kotlin
val shouldShowPlayButton: Boolean = Util.shouldShowPlayButton(player) playPauseButton.setImageDrawable(if (shouldShowPlayButton) playDrawable else pauseDrawable) playPauseButton.setOnClickListener { Util.handlePlayPauseButtonAction(player) }
Java
boolean shouldShowPlayButton = Util.shouldShowPlayButton(player); playPauseButton.setImageDrawable(shouldShowPlayButton ? playDrawable : pauseDrawable); playPauseButton.setOnClickListener(view -> Util.handlePlayPauseButtonAction(player));
Écouter les notifications d'état
Le composant d'UI doit ajouter un Player.Listener pour être informé des changements d'état qui nécessitent une mise à jour correspondante de l'UI. Pour en savoir plus, consultez Écouter les événements de lecture.
L'actualisation de l'UI peut être coûteuse, et plusieurs événements de lecteur se produisent souvent en même temps. Pour éviter d'actualiser l'UI trop souvent sur une courte période, il est généralement préférable d'écouter uniquement onEvents et de déclencher les mises à jour de l'UI à partir de là :
Kotlin
player.addListener( object : Player.Listener { override fun onEvents(player: Player, events: Player.Events) { if ( events.containsAny( Player.EVENT_PLAY_WHEN_READY_CHANGED, Player.EVENT_PLAYBACK_STATE_CHANGED, Player.EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED, ) ) { updatePlayPauseButton() } if (events.containsAny(Player.EVENT_REPEAT_MODE_CHANGED)) { updateRepeatModeButton() } } } )
Java
player.addListener( new Player.Listener() { @Override public void onEvents(Player player, Player.Events events) { if (events.containsAny( Player.EVENT_PLAY_WHEN_READY_CHANGED, Player.EVENT_PLAYBACK_STATE_CHANGED, Player.EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED)) { updatePlayPauseButton(); } if (events.containsAny(Player.EVENT_REPEAT_MODE_CHANGED)) { updateRepeatModeButton(); } } });
Gérer les commandes disponibles
Un composant d'interface utilisateur à usage général qui peut avoir besoin de fonctionner avec différentes implémentations de Player doit vérifier les commandes de lecteur disponibles pour afficher ou masquer les boutons et éviter d'appeler des méthodes non compatibles :
Kotlin
nextButton.isEnabled = player.isCommandAvailable(COMMAND_SEEK_TO_NEXT)
Java
nextButton.setEnabled(player.isCommandAvailable(COMMAND_SEEK_TO_NEXT));
Obturateur et affichage de la première image
Lorsqu'un composant d'interface utilisateur affiche une vidéo ou des images, il utilise généralement une vue d'obturateur d'espace réservé jusqu'à ce que la première image réelle soit disponible. De plus, la lecture mixte de vidéos et d'images nécessite de masquer et d'afficher la vue d'image aux moments appropriés.
Un modèle courant pour gérer ces mises à jour consiste à écouter Player.Listener.onEvents() pour détecter tout changement dans les pistes sélectionnées (EVENT_TRACKS_CHANGED) et lorsque la première image vidéo a été affichée (EVENT_RENDERED_FIRST_FRAME), ainsi que ImageOutput.onImageAvailable() lorsqu'une nouvelle image est disponible :
Kotlin
override fun onEvents(player: Player, events: Player.Events) { if (events.contains(Player.EVENT_TRACKS_CHANGED)) { // If no video or image track: show shutter, hide image view. // Otherwise: do nothing to wait for first frame or image. } if (events.contains(Player.EVENT_RENDERED_FIRST_FRAME)) { // Hide shutter, hide image view. } } override fun onImageAvailable(presentationTimeUs: Long, bitmap: Bitmap) { // Show shutter, set image and show image view. }
Java
@Override public void onEvents(Player player, Player.Events events) { if (events.contains(Player.EVENT_TRACKS_CHANGED)) { // If no video or image track: show shutter, hide image view. // Otherwise: do nothing to wait for first frame or image. } if (events.contains(Player.EVENT_RENDERED_FIRST_FRAME)) { // Hide shutter, hide image view. } } @Override public void onImageAvailable(long presentationTimeUs, Bitmap bitmap) { // Show shutter, set image and show image view. }