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

ב-Media3 יש ערך ברירת מחדל של PlayerView שמספק כמה אפשרויות התאמה אישית.

שינוי של רכיבי drawable

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

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

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

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

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