يوفّر Media3 PlayerView
تلقائيًا يتيح بعض
خيارات التخصيص. لإجراء أي عمليات تخصيص أخرى، على مطوّري التطبيقات
تنفيذ مكونات واجهة المستخدم الخاصة بهم.
أفضل الممارسات
عند تنفيذ واجهة مستخدم للوسائط تتصل بعنصر Player
في Media3 (مثل
ExoPlayer
أو MediaController
أو تنفيذ Player
مخصّص)، ننصح التطبيقات
باتّباع أفضل الممارسات التالية للحصول على أفضل تجربة لواجهة المستخدم.
زر التشغيل/الإيقاف المؤقت
لا يرتبط زرّا التشغيل والإيقاف مؤقتًا مباشرةً بحالة مشغّل واحد. على سبيل المثال، يجب أن يتمكّن المستخدم من إعادة تشغيل المحتوى بعد انتهائه أو تعذّر تشغيله حتى إذا لم يكن المشغّل متوقفًا مؤقتًا.
لتبسيط عملية التنفيذ، يوفّر Media3 طرقًا مساعدة لتحديد
الزر الذي سيتم عرضه (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));
الاستماع إلى آخر المعلومات حول الحالة
يجب أن يضيف مكوّن واجهة المستخدم Player.Listener
ليتم إعلامه بتغييرات الحالة
التي تتطلّب تعديل واجهة المستخدم المقابلة. راجِع مقالة الاستماع إلى أحداث التشغيل للاطّلاع على التفاصيل.
يمكن أن يكون تحديث واجهة المستخدم مكلفًا، وغالبًا ما تصل أحداث اللاعبين المتعدّدة
معًا. لتجنُّب إعادة تحميل واجهة المستخدم بشكل متكرّر خلال فترة زمنية قصيرة، من المفضّل عمومًا الاستماع إلى onEvents
فقط وبدء تعديلات واجهة المستخدم من هناك:
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(); } } });
الطلبات المتاحة
يجب أن يتحقّق عنصر واجهة المستخدم العام الذي قد يحتاج إلى العمل مع عمليات تنفيذ مختلفة من Player
أوامر المشغّل المتاحة لعرض buttons أو إخفائها وتجنُّب استدعاء طرق غير متوافقة:
Kotlin
nextButton.isEnabled = player.isCommandAvailable(Player.COMMAND_SEEK_TO_NEXT)
Java
nextButton.setEnabled(player.isCommandAvailable(Player.COMMAND_SEEK_TO_NEXT));
مصراع الإطار الأول وعرض الصورة
عندما يعرض مكوّن واجهة المستخدم فيديو أو صورًا، يستخدم عادةً عنصر نائب عرض غالق إلى أن يصبح أول إطار أو صورة حقيقيَين متوفّرَين. بالإضافة إلى ذلك، عند تشغيل فيديوهات وصور مختلطة، يجب إخفاء عرض الصورة وإظهاره في الأوقات المناسبة.
من الشائع معالجة هذه التعديلات من خلال الاستماع إلى
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. }