Tuỳ chỉnh giao diện người dùng

Media3 cung cấp PlayerView mặc định, trong đó có một số tuỳ chọn tuỳ chỉnh.

Ghi đè đối tượng có thể vẽ

PlayerView sử dụng PlayerControlView để hiển thị bộ điều khiển chế độ phát và thanh tiến trình. Bạn có thể ghi đè các đối tượng có thể vẽ mà PlayerControlView sử dụng bằng các đối tượng có thể vẽ có cùng tên được xác định trong ứng dụng của bạn. Hãy xem tài liệu PlayerControlView để biết danh sách các đối tượng có thể vẽ điều khiển có thể bị ghi đè.

Để tuỳ chỉnh thêm, nhà phát triển ứng dụng cần triển khai các thành phần giao diện người dùng của riêng họ. Tuy nhiên, dưới đây là một số phương pháp hay nhất có thể giúp bạn bắt đầu.

Các phương pháp hay nhất

Khi triển khai giao diện người dùng nội dung nghe nhìn kết nối với Media3 Player (ví dụ: ExoPlayer, MediaController hoặc cách triển khai Player tuỳ chỉnh), các ứng dụng nên làm theo các phương pháp hay nhất sau đây để có trải nghiệm giao diện người dùng tốt nhất.

Nút phát/tạm dừng

Nút phát và tạm dừng không tương ứng trực tiếp với một trạng thái trình phát. Ví dụ: người dùng có thể bắt đầu lại quá trình phát sau khi quá trình này kết thúc hoặc không thành công, ngay cả khi trình phát không bị tạm dừng.

Để đơn giản hoá việc triển khai, Media3 cung cấp các phương thức tiện ích để quyết định nút nào sẽ hiển thị (Util.shouldShowPlayButton) và xử lý các thao tác nhấn nút (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));

Lắng nghe thông tin cập nhật trạng thái

Thành phần giao diện người dùng cần thêm Player.Listener để được thông báo về các thay đổi trạng thái cần cập nhật giao diện người dùng tương ứng. Hãy xem bài viết Lắng nghe sự kiện phát để biết thông tin chi tiết.

Việc làm mới giao diện người dùng có thể tốn kém và nhiều sự kiện của người chơi thường diễn ra cùng lúc. Để tránh làm mới giao diện người dùng quá thường xuyên trong một khoảng thời gian ngắn, bạn nên chỉ nghe onEvents và kích hoạt các bản cập nhật giao diện người dùng từ đó:

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

Xử lý các lệnh có sẵn

Thành phần giao diện người dùng đa năng có thể cần hoạt động với nhiều cách triển khai Player khác nhau nên kiểm tra các lệnh hiện có của trình phát để hiện hoặc ẩn các nút và tránh gọi các phương thức không được hỗ trợ:

Kotlin

nextButton.isEnabled = player.isCommandAvailable(COMMAND_SEEK_TO_NEXT)

Java

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

Màn trập khung hình đầu tiên và màn hình hiển thị hình ảnh

Khi một thành phần giao diện người dùng hiển thị video hoặc hình ảnh, thành phần đó thường sử dụng chế độ xem màn trập giữ chỗ cho đến khi có khung hình hoặc hình ảnh thực đầu tiên. Ngoài ra, việc phát kết hợp video và hình ảnh đòi hỏi phải ẩn và hiện chế độ xem hình ảnh vào thời điểm thích hợp.

Một mẫu phổ biến để xử lý các bản cập nhật này là nghe Player.Listener.onEvents() để biết mọi thay đổi trong các bản nhạc đã chọn (EVENT_TRACKS_CHANGED) và thời điểm khung video đầu tiên được kết xuất (EVENT_RENDERED_FIRST_FRAME), cũng như ImageOutput.onImageAvailable() để biết thời điểm có hình ảnh mới:

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

Thanh tua và thanh điều khiển tua

Khi triển khai thanh tua hoặc dấu chấm tua tuỳ chỉnh kết nối với một thực thể ExoPlayer, hãy bật chế độ kéo để tua bằng ExoPlayer.setScrubbingModeEnabled khi người dùng bắt đầu kéo dấu chấm tua, gửi thông tin cập nhật Player.seekTo trong khi kéo và tắt chế độ kéo để tua ngay khi cử chỉ kết thúc hoặc bị huỷ. Tránh bật chế độ kéo để tua trong khi phát bình thường hoặc tua một lần, vì chế độ này sẽ chặn quá trình phát và tăng mức sử dụng tài nguyên của bộ giải mã.

Bạn cũng nên định cấu hình dung sai tua phân số dựa trên dp từ chiều rộng của thanh tua giao diện người dùng bằng cách sử dụng ScrubbingModeParameters.Builder.setFractionalSeekTolerance để ExoPlayer có thể chuyển nhanh đến các khung hình chính lân cận trong phạm vi độ chính xác khi chạm của thanh tua. Để biết các ví dụ về mã và thông tin chi tiết, hãy xem phần Chế độ kéo để tua.