Media3 fournit un PlayerView
par défaut qui offre certaines options de personnalisation.
Ignorer 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 qui peuvent être remplacés.
Pour toute personnalisation supplémentaire, les développeurs d'applications sont censés implémenter leurs propres composants d'UI. Toutefois, voici quelques bonnes pratiques qui peuvent vous aider à vous lancer.
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 UI optimale.
Bouton de lecture/pause
Le bouton de lecture et de 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 choisir le 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 mises à jour d'état
Le composant d'UI doit ajouter un Player.Listener
pour être informé des changements d'état qui nécessitent une mise à jour de l'UI correspondante. 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 arrivent 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'UI à usage général qui peut avoir besoin de fonctionner avec différentes implémentations Player
doit vérifier les commandes du lecteur disponibles pour afficher ou masquer les boutons et éviter d'appeler des méthodes non compatibles :
Kotlin
nextButton.isEnabled = player.isCommandAvailable(Player.COMMAND_SEEK_TO_NEXT)
Java
nextButton.setEnabled(player.isCommandAvailable(Player.COMMAND_SEEK_TO_NEXT));
Obturateur de la première image et affichage de l'image
Lorsqu'un composant d'UI affiche une vidéo ou des images, il utilise généralement une vue d'obturation d'espace réservé jusqu'à ce que le premier frame ou la première image réels soient disponibles. De plus, la lecture de vidéos et d'images mixtes nécessite de masquer et d'afficher la vue d'image aux moments appropriés.
Un schéma courant pour gérer ces mises à jour consiste à écouter Player.Listener.onEvents()
pour tout changement dans les pistes sélectionnées (EVENT_TRACKS_CHANGED
) et lorsque la première image vidéo a été rendue (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, 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. }