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

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

Переопределение рисунков

PlayerView использует PlayerControlView для отображения элементов управления воспроизведением и индикатора выполнения. Элементы управления, используемые PlayerControlView могут быть переопределены элементами управления с теми же именами, которые определены в вашем приложении. Список элементов управления, которые можно переопределить, см. в документации PlayerControlView

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

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

При реализации пользовательского интерфейса мультимедиа, подключаемого к Player Media3 Player (например, 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.
}