настройки пользовательского интерфейса

Media3 предоставляет PlayerView по умолчанию, который предоставляет некоторые параметры настройки . Ожидается, что для дальнейшей настройки разработчики приложений реализуют свои собственные компоненты пользовательского интерфейса.

Лучшие практики

При реализации пользовательского интерфейса мультимедиа, который подключается к Player Media3 (например, ExoPlayer , MediaController или пользовательская реализация Player ), приложениям рекомендуется следовать этим рекомендациям для обеспечения наилучшего взаимодействия с пользовательским интерфейсом.

Кнопка воспроизведения/паузы

Кнопка воспроизведения и паузы не соответствует напрямую состоянию одного игрока. Например, пользователь должен иметь возможность возобновить воспроизведение после его завершения или сбоя, даже если проигрыватель не поставлен на паузу.

Чтобы упростить реализацию, Media3 предоставляет методы util, позволяющие решить, какую кнопку отображать ( Util.shouldShowPlayButton ) и обрабатывать нажатия кнопок ( Util.handlePlayPauseButtonAction ):

Котлин

val shouldShowPlayButton: Boolean = Util.shouldShowPlayButton(player)
playPauseButton.setImageDrawable(if (shouldShowPlayButton) playDrawable else pauseDrawable)
playPauseButton.setOnClickListener { Util.handlePlayPauseButtonAction(player) }

Ява

boolean shouldShowPlayButton = Util.shouldShowPlayButton(player);
playPauseButton.setImageDrawable(shouldShowPlayButton ? playDrawable : pauseDrawable);
playPauseButton.setOnClickListener(view -> Util.handlePlayPauseButtonAction(player));

Слушайте обновления штата

Компоненту пользовательского интерфейса необходимо добавить Player.Listener , чтобы получать информацию об изменениях состояния, требующих соответствующего обновления пользовательского интерфейса. Подробности см. в разделе «Прослушивание событий воспроизведения» .

Обновление пользовательского интерфейса может оказаться дорогостоящим, и события для нескольких игроков часто происходят одновременно. Чтобы избежать слишком частого обновления пользовательского интерфейса в течение короткого периода времени, обычно лучше слушать только onEvents и запускать обновления пользовательского интерфейса оттуда:

Котлин

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()
    }
  }
})

Ява

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();
    }
  }
});

Обработка доступных команд

Компонент пользовательского интерфейса общего назначения, которому может потребоваться работа с различными реализациями Player должен проверять доступные команды проигрывателя, чтобы отображать или скрывать кнопки и избегать вызова неподдерживаемых методов:

Котлин

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

Ява

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

Затвор первого кадра и отображение изображения

Когда компонент пользовательского интерфейса отображает видео или изображения, он обычно использует вид затвора-заполнителя до тех пор, пока не станет доступен реальный первый кадр или изображение. Кроме того, при совместном воспроизведении видео и изображений необходимо в соответствующие моменты скрывать и показывать изображение.

Общим шаблоном для обработки этих обновлений является прослушивание Player.Listener.onEvents на предмет любых изменений в выбранных дорожках ( EVENT_TRACKS_CHANGED ) и момента рендеринга первого видеокадра ( EVENT_RENDERED_FIRST_FRAME ), а также ImageOutput.onImageAvailable при появлении нового изображения. доступен:

Котлин

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.
}

Ява

@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.
}