В наборе инструментов Leanback UI есть элементы управления воспроизведением, которые обеспечивают улучшенный пользовательский опыт. Для видеоприложений элементы управления воспроизведением поддерживают перемотку видео вперед и назад. Во время перемотки на экране отображаются миниатюры, помогающие перемещаться по видео.
Библиотека включает в себя как абстрактные классы, так и готовые реализации, предоставляющие разработчикам более детальный контроль. Используя готовые реализации, вы можете быстро создать многофункциональное приложение без большого количества кода. Если вам требуется больше возможностей для настройки, вы можете расширить любой из готовых компонентов библиотеки.
Управление и игрок
Инструментарий Leanback UI отделяет интерфейс управления воспроизведением от проигрывателя, воспроизводящего видео. Это достигается с помощью двух компонентов: фрагмента поддержки воспроизведения для отображения элементов управления воспроизведением (и, при необходимости, видео) и адаптера проигрывателя для инкапсуляции медиаплеера.
Фрагмент воспроизведения
В пользовательском интерфейсе вашего приложения следует использовать PlaybackSupportFragment или VideoSupportFragment . Оба содержат элементы управления воспроизведением Leanback:
- Объект
PlaybackSupportFragmentанимирует элементы управления воспроизведением, чтобы скрывать/показывать их по мере необходимости. - Компонент
VideoSupportFragmentнаследуетPlaybackSupportFragmentи содержитSurfaceViewдля рендеринга видео.
Вы можете настроить ObjectAdapter фрагмента, чтобы улучшить пользовательский интерфейс. Например, используйте setAdapter() для добавления строки "Похожие видео".
PlayerAdapter
PlayerAdapter — это абстрактный класс, управляющий базовым медиаплеером. Разработчики могут выбрать готовую реализацию MediaPlayerAdapter или написать собственную реализацию этого класса.
Склеивание деталей
Для соединения фрагмента воспроизведения с плеером необходимо использовать «контрольный связующий элемент». Библиотека Leanback предоставляет два типа таких элементов:
-
PlaybackBannerControlGlueотображает элементы управления воспроизведением во фрагменте воспроизведения в «старом стиле», помещая их на непрозрачный фон. (PlaybackBannerControlGlueзаменяетPlaybackControlGlue, который устарел.) -
PlaybackTransportControlGlueиспользует элементы управления "нового стиля" с прозрачным фоном.

Если вы хотите, чтобы ваше приложение поддерживало перемотку видео, вам необходимо использовать PlaybackTransportControlGlue .
Также необходимо указать «хост-компонент», который связывает компонент с фрагментом воспроизведения, отображает элементы управления воспроизведением в пользовательском интерфейсе и поддерживает их состояние, а также передает события управления воспроизведением обратно компоненту. Хост-компонент должен соответствовать типу фрагмента воспроизведения. Используйте PlaybackSupportFragmentGlueHost с PlaybackFragment и VideoSupportFragmentGlueHost с VideoFragment .
Вот иллюстрация, показывающая, как соединяются между собой элементы управления механизмом наклона спинки кресла:

Код, который связывает ваше приложение воедино, должен находиться внутри PlaybackSupportFragment или VideoSupportFragment , определяющих пользовательский интерфейс.
В следующем примере приложение создает экземпляр класса PlaybackTransportControlGlue , называя его playerGlue , и подключает его VideoSupportFragment к только что созданному MediaPlayerAdapter . Поскольку это VideoSupportFragment код инициализации вызывает setHost() для прикрепления VideoSupportFragmentGlueHost к playerGlue . Этот код находится внутри класса, расширяющего VideoSupportFragment .
Котлин
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() :
Котлин
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() .
Котлин
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() .
Котлин
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 .
