تتضمن مكتبة androidx Leanback عناصر تحكم جديدة في التشغيل توفر تجربة مستخدم محسّنة. بالنسبة إلى تطبيقات الفيديو، تتيح عناصر التحكم في النقل إمكانية ترجيع الفيديو من خلال عناصر التحكم للأمام/للخلف. أثناء التقديم والترجيع على الشاشة، تظهر صور مصغّرة للمساعدة في التنقّل خلال الفيديو.
وتحتوي المكتبة على فصول دراسية مجردة، بالإضافة إلى عمليات تنفيذ مبتكرة توفّر المزيد من التحكّم الدقيق للمطوّرين. باستخدام التطبيقات المُعدة مسبقًا، يمكنك إنشاء تطبيق غني بالميزات بدون الحاجة إلى ترميز كبير. إذا كنت بحاجة إلى مزيد من التخصيص، يمكنك تمديد أي من مكونات المكتبة المنشأة مسبقًا.
عناصر التحكّم والمشغّل
تفصل مكتبة leanback واجهة المستخدم بين عناصر التحكم في النقل والمشغّل الذي يشغل الفيديو. ويتم تحقيق ذلك من خلال مكوّنين: جزء دعم التشغيل الذي يعرض عناصر التحكم في النقل (والفيديو اختياريًا) ومحوّل مشغّل لتغليف مشغّل الوسائط.
جزء التشغيل
يجب أن يستخدم نشاط واجهة المستخدم في تطبيقك
PlaybackSupportFragment
أو
VideoSupportFragment
.
يحتوي كلاهما على عناصر تحكّم في نقل leanback:
- يحرّك
PlaybackSupportFragment
عناصر التحكّم في النقل لإخفائها أو عرضها حسب الحاجة. - ويمتد
VideoSupportFragment
إلىPlaybackSupportFragment
ويحتوي علىSurfaceView
لعرض الفيديو.
يمكنك تخصيص جزء
ObjectAdapter
لتحسين واجهة المستخدم. على سبيل المثال، يمكنك استخدام
setAdapter()
لإضافة صف "الفيديوهات ذات الصلة".
مهايئ المشغّل
PlayerAdapter
هي فئة مجردة تتحكّم في
مشغّل الوسائط الأساسي. ويمكن للمطوّرين اختيار تنفيذ MediaPlayerAdapter
المُنشأ مسبقًا أو كتابة التنفيذ الخاص بهم لهذه الفئة.
لصق القطع معًا
يجب عليك استخدام جزء من "التحكم في الغراء" لتوصيل جزء التشغيل بالمشغّل. توفر مكتبة leanback نوعين من الغراء:
- يرسم
PlaybackBannerControlGlue
عناصر التحكم في النقل في جزء التشغيل في "النمط القديم"، ويضعها داخل خلفية معتمة. (يحلPlaybackBannerControlGlue
محلPlaybackControlGlue
، الذي تم إيقافه). PlaybackTransportControlGlue
يستخدم عناصر تحكم "نمط جديد" بخلفية شفافة.
إذا أردت أن يتيح تطبيقك ميزة "تنقيح الفيديوهات"، عليك استخدام
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.
.