UI 맞춤설정

Media3는 몇 가지 맞춤설정 옵션을 제공하는 기본 PlayerView를 제공합니다. 추가 맞춤설정을 위해 앱 개발자는 자체 UI 구성요소를 구현해야 합니다.

권장사항

Media3 Player (예: ExoPlayer, MediaController 또는 맞춤 Player 구현)에 연결되는 미디어 UI를 구현할 때 앱은 최상의 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) }

자바

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

상태 업데이트 수신 대기

UI 구성요소는 상응하는 UI 업데이트가 필요한 상태 변경사항을 알 수 있도록 Player.Listener를 추가해야 합니다. 자세한 내용은 재생 이벤트 수신 대기를 참고하세요.

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

자바

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 구현과 함께 작동해야 할 수 있는 범용 UI 구성요소는 사용 가능한 플레이어 명령어를 확인하여 버튼을 표시하거나 숨기고 지원되지 않는 메서드 호출을 피해야 합니다.

Kotlin

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

자바

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

첫 번째 프레임 셔터 및 이미지 디스플레이

UI 구성요소가 동영상이나 이미지를 표시할 때는 일반적으로 실제 첫 번째 프레임이나 이미지를 사용할 수 있을 때까지 자리표시자 셔터 뷰를 사용합니다. 또한 혼합된 동영상 및 이미지 재생을 위해서는 적절한 시점에 이미지 뷰를 숨기고 표시해야 합니다.

이러한 업데이트를 처리하는 일반적인 패턴은 선택한 트랙의 변경사항(EVENT_TRACKS_CHANGED), 첫 번째 동영상 프레임이 렌더링된 시점 (EVENT_RENDERED_FIRST_FRAME)에 관한 Player.Listener.onEvents를 리슨하고 새 이미지를 사용할 수 있는 시점에 관한 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.
}