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

تتضمن مكتبة androidx Leanback عناصر تحكم جديدة في التشغيل توفر تجربة مستخدم محسّنة. بالنسبة إلى تطبيقات الفيديو، تتيح عناصر التحكم في النقل إمكانية ترجيع الفيديو من خلال عناصر التحكم للأمام/للخلف. أثناء التقديم والترجيع على الشاشة، تظهر صور مصغّرة للمساعدة في التنقّل خلال الفيديو.

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

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

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

جزء التشغيل

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

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

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

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

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

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

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

غراء للتحكم في النقل من leanback

إذا أردت أن يتيح تطبيقك ميزة "تنقيح الفيديوهات"، عليك استخدام PlaybackTransportControlGlue.

عليك أيضًا تحديد "مضيف لاصق" يربط الغراء بجزء التشغيل، ويرسم عناصر التحكم في النقل في واجهة المستخدم ويحافظ على حالتها، ويمرر أحداث التحكم في النقل إلى الغراء. يجب أن يتطابق المضيف مع نوع جزء التشغيل. يمكن استخدام PlaybackSupportFragmentGlueHost مع PlaybackFragment، وVideoSupportFragmentGlueHost مع VideoFragment.

في ما يلي رسم توضيحي يعرض كيفية تناسب أجزاء عنصر التحكّم في النقل leanback معًا:

غراء للتحكم في النقل من 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. .