تحتوي مجموعة أدوات واجهة مستخدم 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.