Media3 bietet einen Standard-PlayerView mit einigen Anpassungsoptionen.
Drawables überschreiben
PlayerView verwendet PlayerControlView, um die Wiedergabesteuerung und die Fortschrittsanzeige einzublenden. Die von PlayerControlView verwendeten Drawables können durch Drawables mit denselben Namen überschrieben werden, die in Ihrer Anwendung definiert sind. Eine Liste der überschreibbaren Steuerelement-Drawables finden Sie in der Dokumentation zu PlayerControlView.
Für weitere Anpassungen müssen App-Entwickler ihre eigenen UI-Komponenten implementieren. Hier sind jedoch einige Best Practices, die Ihnen den Einstieg erleichtern können.
Best Practices
Wenn du eine Medien-UI implementierst, die eine Verbindung zu einer Media3-Player herstellt (z. B. ExoPlayer, MediaController oder eine benutzerdefinierte Player-Implementierung), solltest du die folgenden Best Practices beachten, um die beste UI-Erfahrung zu erzielen.
Schaltfläche für Wiedergabe/Pause
Die Schaltfläche „Wiedergabe und Pause“ entspricht nicht direkt einem einzelnen Player-Status. Ein Nutzer sollte beispielsweise die Wiedergabe neu starten können, nachdem sie beendet wurde oder fehlgeschlagen ist, auch wenn der Player nicht pausiert ist.
Um die Implementierung zu vereinfachen, bietet Media3 Hilfsmethoden, mit denen entschieden werden kann, welche Schaltfläche angezeigt werden soll (Util.shouldShowPlayButton), und mit denen Schaltflächenbetätigungen verarbeitet werden können (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));
Statusaktualisierungen überwachen
Die UI-Komponente muss einen Player.Listener hinzufügen, um über Statusänderungen informiert zu werden, die eine entsprechende UI-Aktualisierung erfordern. Weitere Informationen finden Sie unter Wiedergabeereignisse abhören.
Das Aktualisieren der Benutzeroberfläche kann aufwendig sein und oft treten mehrere Player-Ereignisse gleichzeitig auf. Damit die Benutzeroberfläche nicht zu oft in kurzer Zeit aktualisiert wird, ist es im Allgemeinen besser, nur auf onEvents zu warten und von dort aus Aktualisierungen der Benutzeroberfläche auszulösen:
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(); } } });
Verfügbare Befehle verarbeiten
Eine allgemeine UI-Komponente, die möglicherweise mit verschiedenen Player-Implementierungen funktionieren muss, sollte die verfügbaren Player-Befehle prüfen, um Schaltflächen ein- oder auszublenden und den Aufruf nicht unterstützter Methoden zu vermeiden:
Kotlin
nextButton.isEnabled = player.isCommandAvailable(COMMAND_SEEK_TO_NEXT)
Java
nextButton.setEnabled(player.isCommandAvailable(COMMAND_SEEK_TO_NEXT));
Auslöser und Bildanzeige für den ersten Frame
Wenn eine UI-Komponente Videos oder Bilder anzeigt, wird in der Regel eine Platzhalter-Shutter-Ansicht verwendet, bis der erste Frame oder das erste Bild verfügbar ist. Außerdem muss bei der gemischten Wiedergabe von Videos und Bildern die Bildansicht zu den entsprechenden Zeiten ein- und ausgeblendet werden.
Ein gängiges Muster für die Verarbeitung dieser Aktualisierungen besteht darin, auf Player.Listener.onEvents() zu warten, um Änderungen an ausgewählten Tracks (EVENT_TRACKS_CHANGED) und das Rendern des ersten Videoframes (EVENT_RENDERED_FIRST_FRAME) zu erkennen, sowie auf ImageOutput.onImageAvailable(), um zu erkennen, wann ein neues Bild verfügbar ist:
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. }