سفارشی‌سازی‌های میانای کاربر

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 را اضافه کند تا از تغییرات وضعیت که نیازمند به‌روزرسانی میانای کاربر مربوطه است مطلع شود. برای جزئیات، گوش دادن به رویدادهای بازپخش را ببینید.

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

کاتلین

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(COMMAND_SEEK_TO_NEXT)

جاوا

nextButton.setEnabled(player.isCommandAvailable(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, 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.
}

کنترل‌های نوار کاوش و لغزنده

هنگام پیاده‌سازی نوار کاوش یا لغزنده سفارشی که به نمونه ExoPlayer متصل می‌شود، وقتی کاربر شروع به کشیدن لغزنده می‌کند، حالت لغزاندن را با ExoPlayer.setScrubbingModeEnabled فعال کنید، به‌روزرسانی‌های Player.seekTo را درطول کشیدن ارسال کنید، و به‌محض پایان یافتن یا لغو شدن اشاره، حالت لغزاندن را غیرفعال کنید. از فعال نگه داشتن حالت پاک‌سازی درطول بازپخش عادی یا جستجوهای تکی خودداری کنید، زیرا این کار بازپخش را متوقف می‌کند و استفاده از منابع رمزگشا را افزایش می‌دهد.

همچنین توصیه می‌کنیم بااستفاده از ScrubbingModeParameters.Builder.setFractionalSeekTolerance، تلورانس جستجوی کسری مبتنی بر dp را از عرض لغزنده واسط کاربر پیکربندی کنید تا ExoPlayer بتواند به فریم‌های کلیدی نزدیک در محدوده دقت لمس لغزنده بچسبد. برای جزئیات و نمونه‌های کد، به حالت پاک‌سازی مراجعه کنید.