Penyesuaian UI

Media3 menyediakan PlayerView default yang menyediakan beberapa opsi penyesuaian.

Mengganti drawable

PlayerView menggunakan PlayerControlView untuk menampilkan kontrol pemutaran dan status progres. Drawable yang digunakan oleh PlayerControlView dapat diganti dengan drawable dengan nama yang sama yang ditentukan dalam aplikasi Anda. Lihat dokumentasi PlayerControlView untuk mengetahui daftar drawable kontrol yang dapat diganti.

Untuk penyesuaian lebih lanjut, developer aplikasi diharapkan menerapkan komponen UI mereka sendiri. Namun, berikut beberapa praktik terbaik yang dapat membantu Anda memulai.

Praktik terbaik

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

Tombol Putar/Jeda

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

Untuk menyederhanakan penerapan, Media3 menyediakan metode util untuk memutuskan tombol mana 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 Mendengarkan peristiwa pemutaran untuk mengetahui detailnya.

Memuat ulang UI dapat memakan biaya dan beberapa peristiwa pemain sering kali tiba bersamaan. Untuk menghindari terlalu sering me-refresh UI dalam waktu singkat, umumnya lebih baik memproses onEvents saja 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 serbaguna yang mungkin perlu berfungsi dengan berbagai implementasi Player 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 menampilkan video atau gambar, komponen UI biasanya menggunakan tampilan rana placeholder hingga frame atau gambar pertama yang sebenarnya tersedia. Selain itu, pemutaran video dan gambar campuran mengharuskan tampilan gambar disembunyikan dan ditampilkan pada waktu yang tepat.

Pola umum untuk menangani update ini adalah dengan memantau 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() 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.
}