La libreria Leanback Androidx ha nuovi controlli di riproduzione che offrono un'esperienza utente migliore. Per le app video, i controlli di trasporto supportano lo scrubbing video con i controlli avanti/indietro. Mentre esegui lo scrubbing del display, vengono visualizzate delle miniature per facilitare la navigazione.
La libreria include classi astratte e implementazioni predefinite che forniscono un controllo più granulare per gli sviluppatori. Utilizzando le implementazioni predefinite, puoi creare rapidamente un'app ricca di funzionalità senza dover scrivere molto codice. Se hai bisogno di una maggiore personalizzazione, puoi estendere qualsiasi componente predefinito della libreria.
Controlli e player
La libreria Leanback separa l'interfaccia utente con i controlli di trasporto dal player che riproduce il video. A questo scopo, utilizza due componenti: un frammento di supporto per la riproduzione per visualizzare i controlli di trasporto (e, facoltativamente, il video) e un adattatore per il player per incapsulare un media player.
Frammento di riproduzione
L'Attività UI dell'app deve utilizzare un
PlaybackSupportFragment
o un
VideoSupportFragment
.
Entrambi contengono i controlli per il trasporto Leanback:
- Un'
PlaybackSupportFragment
anima i suoi controlli di trasporto per nasconderli/mostrarli in base alle esigenze. - Un elemento
VideoSupportFragment
estendePlaybackSupportFragment
e haSurfaceView
per eseguire il rendering del video.
Puoi personalizzare l'elemento
ObjectAdapter
di un frammento per migliorare l'UI. Ad esempio, utilizza setAdapter()
per aggiungere una riga "video correlati".
Adattatore Player
PlayerAdapter
è una classe astratta che
controlla il media player sottostante. Gli sviluppatori possono scegliere l'implementazione MediaPlayerAdapter
predefinita o scrivere la propria implementazione di questa classe.
Incollamento dei pezzi
Devi usare una "colla di controllo" per collegare il frammento di riproduzione al player. La libreria Leanback offre due tipi di colla:
PlaybackBannerControlGlue
disegna i controlli di trasporto nel frammento di riproduzione nel "vecchio stile", posizionandoli su uno sfondo opaco. (PlaybackBannerControlGlue
sostituiscePlaybackControlGlue
, che è deprecato).PlaybackTransportControlGlue
utilizza i controlli "nuovo stile" con uno sfondo trasparente.
Se vuoi che la tua app supporti l'esecuzione dello scrubbing video, devi usare
PlaybackTransportControlGlue
.
Devi inoltre specificare un "collante host" che
lega il colla al frammento di riproduzione,
disegna i controlli di trasporto nell'interfaccia utente e ne mantiene lo stato e
trasmette di nuovo gli eventi di controllo del trasporto. L'host deve corrispondere al tipo di frammento di riproduzione. Usa
PlaybackSupportFragmentGlueHost
con
PlaybackFragment
e
VideoSupportFragmentGlueHost
con
VideoFragment
.
Ecco un'illustrazione che mostra come si combinano gli elementi di un controllo di trasporto Leanback:
Il codice che collega la tua app deve trovarsi all'interno dell'elemento PlaybackSupportFragment
o VideoSupportFragment
che definisce l'interfaccia utente.
Nell'esempio
seguente, l'app crea un'istanza di PlaybackTransportControlGlue
,
denominandola playerGlue
,
e connette VideoSupportFragment
a un MediaPlayerAdapter
appena creato. Poiché questo è un VideoSupportFragment
, il codice di configurazione chiama setHost()
per collegare un VideoSupportFragmentGlueHost
a playerGlue
. Il codice è incluso nella classe
che estende 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)); } }
Tieni presente che il codice di configurazione definisce anche un PlayerAdapter.Callback
per gestire gli eventi dal media player.
Personalizzazione della colla UI
Puoi personalizzare PlaybackBannerControlGlue
e PlaybackTransportControlGlue
per modificare il PlaybackControlsRow
.
Personalizzazione del titolo e della descrizione
Per personalizzare il titolo e la descrizione nella parte superiore dei controlli di riproduzione, sostituisci 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; }
Aggiunta di controlli
Il collante di controllo mostra i controlli per le azioni in un PlaybackControlsRow
.
Le azioni in PlaybackControlsRow
sono assegnate a due gruppi: azioni principali e azioni
secondarie. I controlli per il gruppo principale vengono visualizzati sopra la barra di scorrimento e i controlli per il
gruppo secondario vengono visualizzati sotto la barra. Inizialmente, esiste una sola azione principale
per il pulsante di riproduzione/pausa e non è disponibile alcuna azione secondaria.
Puoi aggiungere azioni ai gruppi principali e secondari eseguendo l'override di 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); }
Devi eseguire l'override di onActionClicked()
per gestire le nuove azioni.
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. }
In casi speciali, potresti voler implementare le tue
PlaybackTransportRowPresenter
per eseguire il rendering dei controlli personalizzati e rispondere alle azioni di ricerca utilizzando
PlaybackSeekUi
.
Esegui lo scrubbing del video
Se la tua app usa VideoSupportFragment
e vuoi supportare lo scrubbing video.
Devi
fornire un'implementazione di PlaybackSeekDataProvider
.
Questo componente fornisce le miniature dei video utilizzate durante lo scorrimento.
Devi implementare il tuo provider estendendo
PlaybackSeekDataProvider
.
Guarda l'esempio nell'
app Leanback Showcase.