استخدام عناصر التحكّم في النقل

الإنشاء بشكل أفضل باستخدام Compose
يمكنك إنشاء واجهات مستخدم رائعة باستخدام أقل عدد ممكن من الرموز باستخدام Jetpack Compose لنظام التشغيل Android TV.

تتضمّن حزمة أدوات واجهة مستخدِم Leanback عناصر تحكّم في التشغيل توفّر تجربة استخدام محسّنة. في تطبيقات الفيديو، تتيح عناصر التحكّم في النقل تمرير الفيديو سريعًا باستخدام عناصر التحكّم في التقديم والترجيع. تظهر عند مسح الشاشة والصور المصغّرة للمساعدة في التنقل بين أقسام الفيديو.

تتضمّن المكتبة فئات مجردة بالإضافة إلى عمليات تنفيذ مُعدّة مسبقًا ومُعدّة للاستخدام مباشرةً، وتوفر للمطوّرين إمكانية التحكّم بشكل أدق. استخدام واجهة برمجة تطبيقات معدة مسبقًا عمليات التنفيذ، يمكنك إنشاء تطبيق غني بالميزات بسرعة وبدون الحاجة إلى ترميز كثيرًا. إذا كنت بحاجة إلى مزيد من التخصيص، يمكنك توسيع نطاق أيٍّ من المكوّنات المُعدّة مسبقًا في المكتبة.

عناصر التحكّم والمشغّل

تفصل مجموعة أدوات واجهة مستخدم Leanback واجهة المستخدم لعناصر التحكم في النقل المشغّل الذي يشغّل الفيديو. ويتم تحقيق ذلك من خلال عنصرين: جزء دعم التشغيل لعرض عناصر التحكم في النقل (و فيديو اختياريًا) ومحوّل مشغّل لتغليف مشغّل وسائط.

جزء من الفيديو

يجب أن يستخدم نشاط واجهة المستخدم في تطبيقك ملفًا شخصيًا على Google باستخدام PlaybackSupportFragment أو VideoSupportFragment. يحتوي كلاهما على عناصر التحكّم في تشغيل الفيديوهات في وضع الاسترخاء:

  • يعرض PlaybackSupportFragment عناصر التحكّم في النقل بشكل متحرك لإخفائها أو عرضها حسب الحاجة.
  • يمتد نطاق VideoSupportFragment للسمة PlaybackSupportFragment ويتضمّن العنصر SurfaceView لعرض الفيديو.

يمكنك تخصيص طريقة ObjectAdapter لتحسين واجهة المستخدم. على سبيل المثال، استخدِم setAdapter() لإضافة صف "الفيديوهات ذات الصلة".

مهايئ المشغّل

PlayerAdapter هي فئة مجردة تتحكم في مشغّل الوسائط الأساسي. يمكن للمطوّرين الاختيار تنفيذ MediaPlayerAdapter المنشأة مسبقًا أو كتابة كيفية تنفيذها لهذه الفئة.

لصق القطع معًا

يجب استخدام بعض "الغراء" لربط الجزء المخصص للتشغيل للّاعب. The leanback المكتبة نوعين من الغراء هما:

  • PlaybackBannerControlGlue يرسم عناصر التحكّم في التشغيل في جزء التشغيل "بالطراز القديم"، ويضع هذه العناصر داخل خلفية غير شفافة. (PlaybackBannerControlGlue يحلّ محلّ PlaybackControlGlue الذي تم إيقافه نهائيًا).
  • PlaybackTransportControlGlue يستخدم عناصر تحكّم "بالنمط الجديد" مع خلفية شفافة.

عنصر التحكّم في النقل في وضع "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;
}

جارٍ إضافة عناصر التحكّم

يعرض غراء التحكّم عناصر تحكّم في الإجراءات في "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 .