Penyesuaian UI

Media3 menyediakan PlayerView default yang menyediakan beberapa opsi penyesuaian. Untuk penyesuaian lebih lanjut, developer aplikasi diharapkan untuk menerapkan komponen UI mereka sendiri.

Praktik terbaik

Saat menerapkan UI media yang terhubung ke Player Media3 (misalnya ExoPlayer, MediaController, atau implementasi Player kustom), aplikasi dianjurkan untuk mengikuti praktik terbaik ini untuk pengalaman UI terbaik.

Tombol Putar/Jeda

Tombol putar dan jeda tidak langsung sesuai dengan status satu pemain. Misalnya, pengguna harus dapat memulai ulang pemutaran setelah berakhir atau gagal meskipun pemutar tidak dijeda.

Untuk menyederhanakan implementasi, Media3 menyediakan metode utilitas untuk menentukan tombol yang akan ditampilkan (Util.shouldShowPlayButton) dan untuk menangani penekanan tombol (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));

Memproses pembaruan status

Komponen UI perlu menambahkan Player.Listener untuk diberi tahu tentang perubahan status yang memerlukan update UI yang sesuai. Lihat Memproses peristiwa pemutaran untuk mengetahui detailnya.

Memuat ulang UI dapat menghabiskan banyak biaya dan beberapa peristiwa pemain sering kali datang bersamaan. Untuk menghindari terlalu sering memuat ulang UI dalam waktu singkat, sebaiknya hanya memproses onEvents dan memicu update UI dari sana:

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

Menangani perintah yang tersedia

Komponen UI tujuan umum yang mungkin perlu berfungsi dengan implementasi Player yang berbeda harus memeriksa perintah pemutar yang tersedia untuk menampilkan atau menyembunyikan tombol dan untuk menghindari pemanggilan metode yang tidak didukung:

Kotlin

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

Java

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

Shutter frame pertama dan tampilan gambar

Saat komponen UI menampilkan video atau gambar, komponen tersebut biasanya menggunakan tampilan shutter placeholder hingga frame atau gambar pertama yang sebenarnya tersedia. Selain itu, pemutaran video dan gambar campuran memerlukan tindakan menyembunyikan dan menampilkan tampilan gambar pada waktu yang tepat.

Pola umum untuk menangani update ini adalah dengan memproses Player.Listener.onEvents untuk setiap perubahan pada trek yang dipilih (EVENT_TRACKS_CHANGED) dan saat frame video pertama telah dirender (EVENT_RENDERED_FIRST_FRAME), serta ImageOutput.onImageAvailable untuk saat gambar baru tersedia:

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