UI 自訂

Media3 提供預設的 PlayerView,可提供一些自訂選項。如需進一步自訂,應用程式開發人員應實作自己的 UI 元件。

最佳做法

在實作連結至 Media3 Player 的媒體 UI (例如 ExoPlayerMediaController 或自訂 Player 實作) 時,建議應用程式遵循下列最佳做法,以提供最佳 UI 體驗。

播放/暫停按鈕

播放和暫停按鈕並未直接對應單一玩家狀態。舉例來說,即使播放器未暫停,使用者仍應能在播放結束或失敗後重新開始播放。

為了簡化實作方式,Media3 提供實用方法,用於決定要顯示哪個按鈕 (Util.shouldShowPlayButton) 以及處理按鈕按下動作 (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));

監聽狀態更新

UI 元件需要新增 Player.Listener,才能得知需要對應 UI 更新的狀態變更。詳情請參閱「監聽播放事件」。

重新整理 UI 的成本可能很高,而且玩家事件經常會同時發生。為避免在短時間內過度頻繁重新整理 UI,建議您只監聽 onEvents,並從中觸發 UI 更新:

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

處理可用的指令

一般用途的 UI 元件可能需要與不同的 Player 實作搭配運作,因此應檢查可用的播放器指令,以便顯示或隱藏按鈕,並避免呼叫不支援的方法:

Kotlin

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

Java

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

第一個影格快門和圖片顯示

當 UI 元件顯示影片或圖片時,通常會使用預留位置快門檢視畫面,直到實際的第一個影格或圖片可供使用為止。此外,混合式影片和圖片播放功能需要在適當時間隱藏和顯示圖片檢視畫面。

處理這些更新的常見模式是監聽 Player.Listener.onEvents,瞭解所選音軌 (EVENT_TRACKS_CHANGED) 是否有任何變更,以及第一個影片影格是否已算繪 (EVENT_RENDERED_FIRST_FRAME),以及 ImageOutput.onImageAvailable 是否有新圖片:

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