Media3 cung cấp một PlayerView
mặc định cung cấp một số tuỳ chọn tuỳ chỉnh. Đối với mọi hoạt động tuỳ chỉnh khác, 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ọ.
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 Player
Media3 (ví dụ: ExoPlayer
, MediaController
hoặc triển khai Player
tuỳ chỉnh), các ứng dụng nên tuân 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 trực tiếp tương ứng với trạng thái của một người chơi. Ví dụ: người dùng phải có thể bắt đầu lại quá trình phát sau khi quá trình phát 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 hữu í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));
Theo dõi thông tin cập nhật về 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 về trạng thái cần cập nhật giao diện người dùng tương ứng. Hãy xem phần 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 đến cùng một 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, tốt nhất 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
Một thành phần giao diện người dùng có mục đích chung có thể cần phải 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 có sẵn của người chơi để hiển thị 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(Player.COMMAND_SEEK_TO_NEXT)
Java
nextButton.setEnabled(player.isCommandAvailable(Player.COMMAND_SEEK_TO_NEXT));
Màn hình hiển thị hình ảnh và màn trập khung đầu tiên
Khi một thành phần trê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 phần giữ chỗ cho đến khi có khung hình hoặc hình ảnh đầu tiên thực sự. Ngoài ra, chế độ phát video và hình ảnh kết hợp yêu cầu ẩn và hiển thị 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 kênh đã chọn (EVENT_TRACKS_CHANGED
) và thời điểm khung hình video đầu tiên được kết xuất (EVENT_RENDERED_FIRST_FRAME
), cũng như ImageOutput.onImageAvailable
khi 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, 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. }