Anpassungen der Benutzeroberfläche

Media3 bietet eine Standard-PlayerView mit einigen Anpassungsoptionen.

Drawables überschreiben

PlayerView verwendet PlayerControlView, um die Wiedergabesteuerung und die Fortschrittsanzeige darzustellen. Die von PlayerControlView verwendeten Drawables können durch Drawables mit denselben Namen überschrieben werden, die in Ihrer Anwendung definiert sind. Eine Liste der Steuerelement-Drawables, die überschrieben werden können, finden Sie in der Dokumentation zu PlayerControlView.

Für weitere Anpassungen müssen App-Entwickler eigene UI-Komponenten implementieren. Hier sind 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 eine optimale UI-Erfahrung befolgen.

Schaltfläche „Wiedergabe/Pause“

Die Schaltfläche „Wiedergabe und Pause“ entspricht nicht direkt einem einzelnen Playerstatus. 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 Sie entscheiden können, welche Schaltfläche angezeigt werden soll (Util.shouldShowPlayButton), und Schaltflächenklicks verarbeiten 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));

Statusupdates anhören

Die UI-Komponente muss ein Player.Listener hinzufügen, um über Zustandsänderungen informiert zu werden, die ein entsprechendes UI-Update erfordern. Weitere Informationen finden Sie unter Wiedergabeereignisse abhören.

Das Aktualisieren der Benutzeroberfläche kann kostspielig sein und mehrere Player-Ereignisse kommen oft gleichzeitig an. Um zu vermeiden, dass die Benutzeroberfläche in kurzer Zeit zu oft aktualisiert wird, ist es in der Regel besser, nur auf onEvents zu warten und UI-Updates 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 universelle UI-Komponente, die möglicherweise mit verschiedenen Player-Implementierungen verwendet wird, sollte die verfügbaren Player-Befehle prüfen, um Schaltflächen ein- oder auszublenden und das Aufrufen nicht unterstützter Methoden zu vermeiden:

Kotlin

nextButton.isEnabled = player.isCommandAvailable(Player.COMMAND_SEEK_TO_NEXT)

Java

nextButton.setEnabled(player.isCommandAvailable(Player.COMMAND_SEEK_TO_NEXT));

Erster Frame-Verschluss und Bildanzeige

Wenn in einer UI-Komponente Videos oder Bilder angezeigt werden, wird in der Regel ein Platzhalter-Shutter-View 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 geeigneten Zeiten ein- und ausgeblendet werden.

Ein gängiges Muster für die Verarbeitung dieser Aktualisierungen besteht darin, auf Player.Listener.onEvents() zu warten, wenn sich die ausgewählten Tracks (EVENT_TRACKS_CHANGED) ändern und wenn der erste Videoframes gerendert wurde (EVENT_RENDERED_FIRST_FRAME), sowie auf ImageOutput.onImageAvailable(), wenn 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, 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.
}