התאמות אישיות של ממשק המשתמש

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 וההטמעות צריכות לבדוק את פקודות הנגן הזמינות להצגה או להסתרה וכדי להימנע משליחת קריאה לשיטות לא נתמכות:

Kotlin

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

Java

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

תריס הפריים הראשון ותצוגת התמונה

כשרכיב בממשק המשתמש מציג סרטונים או תמונות, בדרך כלל הוא משתמש ב-placeholder עד שהפריים או התמונה הראשונים האמיתיים יהיו זמינים. In addition, להפעלה משולבת של סרטונים ותמונות נדרשת הסתרה והצגה של תצוגת התמונה ב בזמנים המתאימים.

דפוס נפוץ לטיפול בעדכונים האלה הוא להאזין 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.
}