سفارشی سازی UI

Media3 یک PlayerView پیش‌فرض ارائه می‌کند که برخی از گزینه‌های سفارشی‌سازی را ارائه می‌کند.

موارد قابل ترسیم را لغو کنید

PlayerView از PlayerControlView برای نمایش کنترل های پخش و نوار پیشرفت استفاده می کند. نقشه‌هایی که توسط PlayerControlView استفاده می‌شوند، می‌توانند توسط نقشه‌هایی با همان نام‌های تعریف‌شده در برنامه شما لغو شوند. برای فهرستی از نقشه‌های کنترلی که می‌توان آنها را نادیده گرفت، به مستندات PlayerControlView مراجعه کنید.

برای هر گونه سفارشی سازی بیشتر، از توسعه دهندگان برنامه انتظار می رود اجزای رابط کاربری خود را پیاده سازی کنند. با این حال، در اینجا برخی از بهترین روش ها وجود دارد که می تواند به شما در شروع کار کمک کند.

بهترین شیوه ها

هنگام پیاده‌سازی یک رابط کاربری رسانه‌ای که به Media3 Player متصل می‌شود (به عنوان مثال ExoPlayer ، MediaController یا پیاده‌سازی Player سفارشی)، به برنامه‌ها توصیه می‌شود این بهترین شیوه‌ها را برای بهترین تجربه رابط کاربری دنبال کنند.

دکمه پخش/مکث

دکمه پخش و مکث مستقیماً با یک حالت پخش کننده مطابقت ندارد. به عنوان مثال، یک کاربر باید بتواند پس از پایان یافتن یا شکست آن، حتی اگر پخش کننده متوقف نشده باشد، پخش را مجدداً راه اندازی کند.

برای ساده‌سازی پیاده‌سازی، Media3 روش‌هایی را برای تصمیم‌گیری اینکه کدام دکمه نمایش داده شود ( Util.shouldShowPlayButton ) و برای کنترل فشار دادن دکمه ( Util.handlePlayPauseButtonAction ) ارائه می‌کند:

val shouldShowPlayButton: Boolean = Util.shouldShowPlayButton(player)
playPauseButton.setImageDrawable(if (shouldShowPlayButton) playDrawable else pauseDrawable)
playPauseButton.setOnClickListener { Util.handlePlayPauseButtonAction(player) }
boolean shouldShowPlayButton = Util.shouldShowPlayButton(player);
playPauseButton.setImageDrawable(shouldShowPlayButton ? playDrawable : pauseDrawable);
playPauseButton.setOnClickListener(view -> Util.handlePlayPauseButtonAction(player));

به به روز رسانی های ایالت گوش دهید

مؤلفه رابط کاربری باید یک Player.Listener اضافه کند تا از تغییرات وضعیتی که نیاز به به‌روزرسانی رابط کاربری مربوطه دارند مطلع شود. برای جزئیات بیشتر به گوش دادن به رویدادهای پخش مراجعه کنید.

تازه کردن رابط کاربری ممکن است پرهزینه باشد و رویدادهای چند بازیکن اغلب با هم می آیند. برای جلوگیری از به‌روزرسانی بیش از حد UI در مدت زمان کوتاه، معمولاً بهتر است فقط به onEvents گوش دهید و به‌روزرسانی‌های UI را از آنجا فعال کنید:

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

کنترل دستورات موجود

یک مؤلفه رابط کاربری عمومی که ممکن است نیاز به کار با پیاده سازی های مختلف Player داشته باشد، باید دستورات پخش کننده موجود را برای نمایش یا پنهان کردن دکمه ها و جلوگیری از فراخوانی روش های پشتیبانی نشده بررسی کند:

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

اولین شاتر فریم و نمایش تصویر

هنگامی که یک مؤلفه رابط کاربری ویدیو یا تصاویر را نمایش می دهد، معمولاً از نمای شاتر نگهدارنده استفاده می کند تا زمانی که اولین فریم یا تصویر واقعی در دسترس باشد. علاوه بر این، پخش ترکیبی ویدیو و تصویر نیاز به پنهان کردن و نمایش تصویر در زمان‌های مناسب دارد.

یک الگوی رایج برای رسیدگی به این به‌روزرسانی‌ها، گوش دادن به Player.Listener.onEvents() برای هرگونه تغییر در آهنگ‌های انتخابی ( EVENT_TRACKS_CHANGED ) و زمانی که اولین فریم ویدیو رندر شده است ( EVENT_RENDERED_FIRST_FRAME )، و همچنین ImageOutput.onImageAvailable() برای زمانی که یک تصویر جدید در دسترس است.

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