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

‫Media3 מספקת PlayerView שמוגדר כברירת מחדל ומאפשר כמה אפשרויות להתאמה אישית.

שינוי של משאבי drawable

PlayerView משתמש ב-PlayerControlView כדי להציג את אמצעי הבקרה של ההפעלה ואת סרגל ההתקדמות. אפשר להחליף את הנכסים הגרפיים שמשמשים את PlayerControlView בנכסים גרפיים עם אותם שמות שמוגדרים באפליקציה. PlayerControlView במסמכי התיעוד מופיעה רשימה של רכיבי drawable של אמצעי בקרה שאפשר לבטל.

לכל התאמה אישית נוספת, מפתחי אפליקציות צריכים להטמיע רכיבי ממשק משתמש משלהם. עם זאת, הנה כמה שיטות מומלצות שיעזרו לכם להתחיל.

שיטות מומלצות

כשמטמיעים ממשק משתמש של מדיה שמתחבר ל-Media3 Player (לדוגמה 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();
    }
  }
});

הפקודות הזמינות

רכיב UI לשימוש כללי שאולי צריך לפעול עם יישומי Player שונים צריך לבדוק את פקודות הנגן הזמינות כדי להציג או להסתיר כפתורים, וכדי להימנע מהפעלת שיטות שלא נתמכות:

Kotlin

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

Java

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

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

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

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