Media3 bietet eine Standard-PlayerView mit einigen Anpassungs
optionen.
Zeichnungen überschreiben
PlayerView verwendet PlayerControlView, um die Wiedergabesteuerung und die Fortschrittsanzeige anzuzeigen. Die von PlayerControlView verwendeten Zeichnungen können durch Zeichnungen mit denselben Namen überschrieben werden, die in Ihrer Anwendung definiert sind. Eine Liste der Zeichnungen für die Steuerung, die
überschrieben werden können, finden Sie in der
PlayerControlView Dokumentation zu.
Für weitere Anpassungen müssen App-Entwickler eigene UI-Komponenten implementieren. Hier sind jedoch einige Best Practices, die Ihnen den Einstieg erleichtern können.
Best Practices
Bei der Implementierung einer Medien-UI, die mit einem Media3 Player verbunden ist (z. B.
ExoPlayer, MediaController oder eine benutzerdefinierte Player-Implementierung), sollten Apps
diese Best Practices für die bestmögliche UI-Erfahrung befolgen.
Schaltfläche „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, um zu entscheiden, welche Schaltfläche angezeigt werden soll (Util.shouldShowPlayButton), und um Schaltflächenklicks zu verarbeiten (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 abhören
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 Wiedergabe
ereignisse abhören.
Das Aktualisieren der UI kann kostspielig sein und mehrere Player-Ereignisse kommen oft gleichzeitig an. Um die UI nicht zu oft in kurzer Zeit zu aktualisieren, ist es im Allgemeinen besser, nur auf onEvents zu hören und UI-Aktualisierungen von dort aus 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 verwendet werden muss, sollte die verfügbaren Player-Befehle prüfen, um Schaltflächen ein- oder auszublenden und zu vermeiden, dass nicht unterstützte Methoden aufgerufen werden:
Kotlin
nextButton.isEnabled = player.isCommandAvailable(COMMAND_SEEK_TO_NEXT)
Java
nextButton.setEnabled(player.isCommandAvailable(COMMAND_SEEK_TO_NEXT));
Erster Frame-Shutter und Bildanzeige
Wenn eine UI-Komponente Videos oder Bilder anzeigt, wird in der Regel ein Platzhalter-Shutter 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 zum Verarbeiten dieser Aktualisierungen besteht darin, auf
Player.Listener.onEvents() nach Änderungen an ausgewählten Tracks
(EVENT_TRACKS_CHANGED) und nach dem Rendern des ersten Video-Frames
(EVENT_RENDERED_FIRST_FRAME) sowie auf ImageOutput.onImageAvailable()
nach dem Verfügbarkeit eines neuen Bildes zu hören:
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. }