การปรับแต่ง UI

Media3 มี PlayerView เริ่มต้นซึ่งมีตัวเลือกการปรับแต่งบางอย่าง

ลบล้าง Drawable

การทำเครื่องหมายรหัสทรัพยากรเป็น "ส่วนตัว"

PlayerView ใช้ PlayerControlView เพื่อแสดงตัวควบคุมการเล่นและ แถบความคืบหน้า PlayerControlView สามารถลบล้าง Drawable ที่ใช้ได้โดย Drawable ที่มีชื่อเดียวกันซึ่งกำหนดไว้ในแอปพลิเคชัน ดูรายการ Drawable ของตัวควบคุมที่สามารถ ลบล้างได้ในเอกสารประกอบของ PlayerControlView

หากต้องการปรับแต่งเพิ่มเติม นักพัฒนาแอปจะต้องใช้คอมโพเนนต์ UI ของตนเอง แต่แนวทางปฏิบัติแนะนำต่อไปนี้จะช่วยให้คุณเริ่มต้นได้

แนวทางปฏิบัติแนะนำ

เมื่อใช้ UI ของสื่อที่เชื่อมต่อกับ Media3 Player (เช่น ExoPlayer, MediaController หรือการใช้งาน Player ที่กำหนดเอง) เราขอแนะนำให้แอปปฏิบัติตามแนวทางปฏิบัติแนะนำเหล่านี้เพื่อให้ได้ประสบการณ์ UI ที่ดีที่สุด

ปุ่มเล่น/หยุดชั่วคราว

ปุ่มเล่นและหยุดชั่วคราวไม่ได้สอดคล้องกับสถานะของเพลเยอร์เดียวโดยตรง ตัวอย่างเช่น ผู้ใช้ควรจะสามารถเริ่มการเล่นใหม่หลังจากที่เล่นจบหรือเล่นไม่สำเร็จ แม้ว่าโปรแกรมเล่นจะไม่ได้หยุดชั่วคราวก็ตาม

Media3 มีเมธอด Util เพื่อช่วยในการตัดสินใจว่าจะแสดงปุ่มใด (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 อาจมีค่าใช้จ่ายสูง และเหตุการณ์ของเพลเยอร์หลายรายการมักจะมาพร้อมกัน โดยทั่วไปแล้ว การฟังเฉพาะ onEvents และทริกเกอร์การอัปเดต UI จากที่นั่นจะดีกว่าเพื่อหลีกเลี่ยงการรีเฟรช 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.
}