O kit de ferramentas de interface do usuário do YouTube tem controles de reprodução que oferecem uma interface experiência do usuário. Para apps de vídeo, os controles de transporte são compatíveis com a barra de progressão de vídeo com os controles para avançar e voltar. Ao arrastar o marcador, a tela mostra miniaturas para ajudar a navegar pelo vídeo.
A biblioteca inclui classes abstratas, bem como implementações pré-criadas e prontas para uso. que oferecem controle mais granular para os desenvolvedores. Usar o modelo você pode criar rapidamente um app repleto de recursos sem muita programação. Se precisar de mais personalização, você pode estender qualquer um dos componentes de solução.
Controles e player
O kit de ferramentas da interface Leanback separa a interface de controles de transporte do player que exibe o vídeo. Isso é feito com dois componentes: um fragmento de suporte à reprodução para exibir os controles de transporte (e, opcionalmente, o vídeo) e um adaptador do player para encapsular um player de mídia.
Fragmento de reprodução
A atividade da IU do seu app precisa usar um
PlaybackSupportFragment
ou um
VideoSupportFragment
.
Ambos contêm os controles de transporte da leanback:
- Um
PlaybackSupportFragment
cria animações para ocultar/exibir os controles de transporte conforme necessário. - Um
VideoSupportFragment
estendePlaybackSupportFragment
e tem umSurfaceView
para renderizar vídeo.
É possível personalizar o
ObjectAdapter
de um fragmento
para melhorar a interface. Por exemplo, use
setAdapter()
para adicionar um "vídeos relacionados" linha de comando.
PlayerAdapter
PlayerAdapter
é uma classe abstrata que
controla o player de mídia subjacente. Os desenvolvedores podem escolher
a implementação da MediaPlayerAdapter
pré-criada ou gravar
a própria implementação dessa classe.
Agrupar as partes
É necessário usar algum "agrupador de controles" para conectar o fragmento de reprodução ao player. O botão de relaxamento fornece dois tipos de cola:
PlaybackBannerControlGlue
desenha o transportar controles no fragmento de reprodução no "estilo antigo", colocando-os dentro de um fundo opaco.PlaybackBannerControlGlue
substituiPlaybackControlGlue
, que foi descontinuado.PlaybackTransportControlGlue
usa "novo estilo" com um plano de fundo transparente.
Se você quer que o app seja compatível com a barra de progressão de vídeo, é necessário usar
PlaybackTransportControlGlue
.
Você também precisa especificar um "host de agrupador" que
vincule o agrupador ao fragmento de
reprodução, desenhe os controles de transporte na IU, mantenha o estado deles e
transmita os eventos de controle de transporte de volta para o agrupador. O host precisa corresponder ao tipo do fragmento de reprodução. Usar
PlaybackSupportFragmentGlueHost
com
um PlaybackFragment
e
VideoSupportFragmentGlueHost
com um
VideoFragment
.
Esta é uma ilustração que mostra como as peças do controle de transporte do Flix se encaixam:
O código que agrupa seu app precisa estar dentro do
PlaybackSupportFragment
ou VideoSupportFragment
que define a IU.
Nos seguintes
exemplo, o app cria uma instância de PlaybackTransportControlGlue
,
dê o nome playerGlue
a ele.
e conecta o VideoSupportFragment
a um MediaPlayerAdapter
recém-criado. Como
este é um VideoSupportFragment
. O código de configuração chama setHost()
para anexar um
VideoSupportFragmentGlueHost
para playerGlue
. O código é incluído na classe
que estende o 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)); } }
O código de configuração também define um PlayerAdapter.Callback
para processar eventos do
o player de mídia.
Personalizar o agrupador da IU
Você pode personalizar
PlaybackBannerControlGlue
e PlaybackTransportControlGlue
para alterar
PlaybackControlsRow
Personalizar o título e a descrição
Para personalizar o título e a descrição na parte superior do
controles de mídia, substituir
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; }
Adicionar controles
O agrupador de controles exibe controles para ações em uma PlaybackControlsRow
.
As ações em PlaybackControlsRow
são atribuídas a dois grupos: ações principais e ações
secundárias. Os controles para o grupo principal aparecem acima da barra de busca e dos controles do
grupo secundário aparecem abaixo da barra de busca. Inicialmente, há apenas uma ação principal
para o botão assistir/pausar, sem qualquer ação secundária.
É possível adicionar ações aos grupos principal e secundário modificando
onCreatePrimaryActions()
e
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); }
Você deve substituir
onActionClicked()
para processar as novas ações.
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. }
Em casos especiais, convém implementar sua própria
PlaybackTransportRowPresenter
para processar controles personalizados e responder a ações de busca usando o
PlaybackSeekUi
.
Barra de progressão de vídeo
Se seu app usa um VideoSupportFragment
e você quer compatibilizar com barra de progressão de vídeo.
É
necessário fornecer uma implementação de PlaybackSeekDataProvider
.
Esse componente exibe miniaturas no vídeo que são usadas ao mover a barra.
Você precisa implementar seu próprio provedor, estendendo
PlaybackSeekDataProvider
:
Confira o exemplo na
App Leanback Showcase (link em inglês).
,