שימוש בבקרות התעבורה

פיתוח יעיל יותר באמצעות Compose
איך יוצרים ממשקי משתמש יפים עם קוד מינימלי באמצעות Jetpack Compose ל-Android TV OS.

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

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

פקדים ונגן

ערכת הכלים לבניית ממשק משתמש ל-Leanback מפרידה בין ממשק המשתמש של בקרות התעבורה הנגן שמפעיל את הסרטון. כדי לעשות זאת, משתמשים בשני רכיבים: קטע תמיכה בהפעלה להצגת פקדי ההעברה (ואם רוצים גם את הסרטון) ומתאם נגן כדי להכיל נגן מדיה.

קטע הפעלה

בפעילות בממשק המשתמש של האפליקציה צריך להשתמש ב- PlaybackSupportFragment או VideoSupportFragment. שניהם כוללים את אמצעי הבקרה להעברות leanback:

  • PlaybackSupportFragment מציג אנימציה של אמצעי הבקרה על התנועה כדי להסתיר או להציג אותם לפי הצורך.
  • VideoSupportFragment הוא תת-ממשק של PlaybackSupportFragment, ויש לו SurfaceView לעיבוד סרטונים.

אפשר להתאים אישית את ObjectAdapter של קטע כדי לשפר את ממשק המשתמש. לדוגמה, השתמשו setAdapter() כדי להוסיף "סרטונים קשורים" השורה הראשונה.

PlayerAdapter

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

הדבקה של החלקים זהב

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

דבק לפקדי התעבורה במצב leanback

אם אתם רוצים שהאפליקציה תתמוך בסריקת וידאו, עליכם להשתמש ב-PlaybackTransportControlGlue.

צריך גם לציין 'מארח דבק' ש מקשרת את הדבק להפעלה מקטע, מצייר את פקדי התעבורה בממשק המשתמש ושומר על המצב שלהם, מעבירה בחזרה את אירועי בקרת ההובלה לדבק. המארח חייב להתאים לסוג קטע ההפעלה. משתמשים ב-PlaybackSupportFragmentGlueHost עם PlaybackFragment וב-VideoSupportFragmentGlueHost עם VideoFragment.

איור שמראה איך חלקי אמצעי הבקרה על התנועה ב-Leanback משתלבים יחד:

דבק לבקרת תעבורה

הקוד שמדביק את האפליקציה צריך להיות בתוך PlaybackSupportFragment או VideoSupportFragment שמגדירים את ממשק המשתמש.

בדוגמה הבאה, האפליקציה יוצרת מופע של PlaybackTransportControlGlue, נותנת לו את השם playerGlue ומקשרת את VideoSupportFragment שלו ל-MediaPlayerAdapter שנוצר לאחרונה. מכיוון שמדובר ב-VideoSupportFragment, קוד ההגדרה קורא ל-setHost() כדי לצרף VideoSupportFragmentGlueHost ל-playerGlue. הקוד נכלל בתוך המחלקה שמרחיבה את VideoSupportFragment.

Kotlin

class MyVideoFragment : VideoSupportFragment() {

  fun onCreate(savedInstanceState: Bundle) {
      super.onCreate(savedInstanceState)
      val playerGlue = PlaybackTransportControlGlue(getActivity(),
          MediaPlayerAdapter(getActivity()))
      playerGlue.setHost(VideoSupportFragmentGlueHost(this))
      playerGlue.addPlayerCallback(object : PlaybackGlue.PlayerCallback() {
          override fun onPreparedStateChanged(glue: PlaybackGlue) {
              if (glue.isPrepared()) {
                  playerGlue.seekProvider = MySeekProvider()
                  playerGlue.play()
              }
          }
      })
      playerGlue.setSubtitle("Leanback artist")
      playerGlue.setTitle("Leanback team at work")
      val uriPath = "android.resource://com.example.android.leanback/raw/video"
      playerGlue.getPlayerAdapter().setDataSource(Uri.parse(uriPath))
  }
}

Java

public class MyVideoFragment extends VideoSupportFragment {

  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      final PlaybackTransportControlGlue<MediaPlayerAdapter> playerGlue =
              new PlaybackTransportControlGlue(getActivity(),
                      new MediaPlayerAdapter(getActivity()));
      playerGlue.setHost(new VideoSupportFragmentGlueHost(this));
      playerGlue.addPlayerCallback(new PlaybackGlue.PlayerCallback() {
          @Override
          public void onPreparedStateChanged(PlaybackGlue glue) {
              if (glue.isPrepared()) {
                  playerGlue.setSeekProvider(new MySeekProvider());
                  playerGlue.play();
              }
          }
      });
      playerGlue.setSubtitle("Leanback artist");
      playerGlue.setTitle("Leanback team at work");
      String uriPath = "android.resource://com.example.android.leanback/raw/video";
      playerGlue.getPlayerAdapter().setDataSource(Uri.parse(uriPath));
  }
}

לתשומת ליבכם: קוד ההגדרה גם מגדיר את הערך PlayerAdapter.Callback לטיפול באירועים מ: נגן המדיה.

התאמה אישית של הדבק של ממשק המשתמש

אפשר להתאים אישית את הערכים של PlaybackBannerControlGlue ו-PlaybackTransportControlGlue כדי לשנות את הערך של PlaybackControlsRow.

התאמה אישית של הכותרת והתיאור

כדי להתאים אישית את השם והתיאור בחלק העליון של פקדי הפעלה, לשנות onCreateRowPresenter():

Kotlin

override fun onCreateRowPresenter(): PlaybackRowPresenter {
    return super.onCreateRowPresenter().apply {
        (this as? PlaybackTransportRowPresenter)
                ?.setDescriptionPresenter(MyCustomDescriptionPresenter())
    }
}

Java

@Override
protected PlaybackRowPresenter onCreateRowPresenter() {
  PlaybackTransportRowPresenter presenter = (PlaybackTransportRowPresenter) super.onCreateRowPresenter();
  presenter.setDescriptionPresenter(new MyCustomDescriptionPresenter());
  return presenter;
}

הוספת פקדים

ב-control glue מוצגים אמצעי בקרה לפעולות ב-PlaybackControlsRow.

הפעולות בPlaybackControlsRow מוקצות לשתי קבוצות: פעולות ראשיות ופעולות משניות פעולות. הפקדים של הקבוצה הראשית מופיעים מעל סרגל הדילוג ופקדים הקבוצה המשנית תופיע מתחת לסרגל הדילוג. בשלב הראשון, יש רק פעולה ראשית אחת ללחצן ההפעלה/השהיה, ואין פעולות משניות.

אפשר להוסיף פעולות לקבוצה הראשית או לקבוצה המשנית על ידי ביטול onCreatePrimaryActions() והקבוצה onCreateSecondaryActions().

Kotlin

private lateinit var repeatAction: PlaybackControlsRow.RepeatAction
private lateinit var pipAction: PlaybackControlsRow.PictureInPictureAction
private lateinit var thumbsUpAction: PlaybackControlsRow.ThumbsUpAction
private lateinit var thumbsDownAction: PlaybackControlsRow.ThumbsDownAction
private lateinit var skipPreviousAction: PlaybackControlsRow.SkipPreviousAction
private lateinit var skipNextAction: PlaybackControlsRow.SkipNextAction
private lateinit var fastForwardAction: PlaybackControlsRow.FastForwardAction
private lateinit var rewindAction: PlaybackControlsRow.RewindAction

override fun onCreatePrimaryActions(primaryActionsAdapter: ArrayObjectAdapter) {
    // Order matters, super.onCreatePrimaryActions() will create the play / pause action.
    // Will display as follows:
    // play/pause, previous, rewind, fast forward, next
    //   > /||      |<        <<        >>         >|
    super.onCreatePrimaryActions(primaryActionsAdapter)
    primaryActionsAdapter.apply {
        add(skipPreviousAction)
        add(rewindAction)
        add(fastForwardAction)
        add(skipNextAction)
    }
}

override fun onCreateSecondaryActions(adapter: ArrayObjectAdapter?) {
    super.onCreateSecondaryActions(adapter)
    adapter?.apply {
        add(thumbsDownAction)
        add(thumbsUpAction)
    }
}

Java

private PlaybackControlsRow.RepeatAction repeatAction;
private PlaybackControlsRow.PictureInPictureAction pipAction;
private PlaybackControlsRow.ThumbsUpAction thumbsUpAction;
private PlaybackControlsRow.ThumbsDownAction thumbsDownAction;
private PlaybackControlsRow.SkipPreviousAction skipPreviousAction;
private PlaybackControlsRow.SkipNextAction skipNextAction;
private PlaybackControlsRow.FastForwardAction fastForwardAction;
private PlaybackControlsRow.RewindAction rewindAction;

@Override
protected void onCreatePrimaryActions(ArrayObjectAdapter primaryActionsAdapter) {
    // Order matters, super.onCreatePrimaryActions() will create the play / pause action.
    // Will display as follows:
    // play/pause, previous, rewind, fast forward, next
    //   > /||      |<        <<        >>         >|
    super.onCreatePrimaryActions(primaryActionsAdapter);
    primaryActionsAdapter.add(skipPreviousAction);
    primaryActionsAdapter.add(rewindAction);
    primaryActionsAdapter.add(fastForwardAction);
    primaryActionsAdapter.add(skipNextAction);
}

@Override
protected void onCreateSecondaryActions(ArrayObjectAdapter adapter) {
    super.onCreateSecondaryActions(adapter);
    adapter.add(thumbsDownAction);
    adapter.add(thumbsUpAction);
}

צריך לשנות את onActionClicked() כדי לטפל בפעולות החדשות.

Kotlin

override fun onActionClicked(action: Action) {
    when(action) {
        rewindAction -> {
            // Handle Rewind
        }
        fastForwardAction -> {
            // Handle FastForward
        }
        thumbsDownAction -> {
            // Handle ThumbsDown
        }
        thumbsUpAction -> {
            // Handle ThumbsUp
        }
        else ->
            // The superclass handles play/pause and delegates next/previous actions to abstract methods,
            // so those two methods should be overridden rather than handling the actions here.
            super.onActionClicked(action)
    }
}

override fun next() {
    // Skip to next item in playlist.
}

override fun previous() {
    // Skip to previous item in playlist.
}

Java

@Override
public void onActionClicked(Action action) {
    if (action == rewindAction) {
        // Handle Rewind
    } else if (action == fastForwardAction ) {
        // Handle FastForward
    } else if (action == thumbsDownAction) {
        // Handle ThumbsDown
    } else if (action == thumbsUpAction) {
        // Handle ThumbsUp
    } else {
        // The superclass handles play/pause and delegates next/previous actions to abstract methods,
        // so those two methods should be overridden rather than handling the actions here.
        super.onActionClicked(action);
    }
}

@Override
public void next() {
    // Skip to next item in playlist.
}

@Override
public void previous() {
    // Skip to previous item in playlist.
}

במקרים מיוחדים, יכול להיות שתרצו להטמיע PlaybackTransportRowPresenter משלכם כדי להציג פקדים בהתאמה אישית ולהגיב לפעולות של סריקה באמצעות PlaybackSeekUi.

סריקה של וידאו

אם האפליקציה שלכם משתמשת ב-VideoSupportFragment ואתם רוצים לתמוך בסריקת סרטונים.

קרצוף

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