Das Leanback-UI-Toolkit bietet Steuerelemente für die Wiedergabe, die für eine bessere Nutzererfahrung sorgen. Bei Video-Apps unterstützen die Transportsteuerelemente das Scrubbing mit der Vorwärts- und Rückwärtssteuerung. Beim Scrubbing werden auf dem Display Thumbnails angezeigt, die die Navigation durch das Video erleichtern.
Die Bibliothek enthält abstrakte Klassen sowie vordefinierte, sofort einsatzbereite Implementierungen, die Entwicklern eine detailliertere Kontrolle ermöglichen. Mithilfe der vordefinierten Implementierungen können Sie schnell und ohne Programmieraufwand eine App mit vielen Funktionen erstellen. Wenn Sie weitere Anpassungen benötigen, können Sie alle vordefinierten Komponenten der Bibliothek erweitern.
Steuerelemente und Player
Das Leanback-UI-Toolkit trennt die UI für Transportsteuerungen vom Player, der das Video wiedergibt. Dies wird durch zwei Komponenten erreicht: ein Wiedergabe-Unterstützungsfragment zum Anzeigen der Transportsteuerelemente (und optional das Video) und einen Player-Adapter zur Kapselung eines Mediaplayers.
Wiedergabefragment
Für die UI-Aktivität deiner App muss PlaybackSupportFragment
oder VideoSupportFragment
verwendet werden.
Beide enthalten die Steuerelemente für den Leanback-Transport:
- Ein
PlaybackSupportFragment
animiert seine Transportsteuerelemente, um sie bei Bedarf ein- oder auszublenden. - Ein
VideoSupportFragment
erweitertPlaybackSupportFragment
und hat einenSurfaceView
zum Rendern von Videos.
Du kannst den ObjectAdapter
eines Fragments anpassen, um die UI zu optimieren. Verwenden Sie beispielsweise setAdapter()
, um die Zeile „Ähnliche Videos“ hinzuzufügen.
Player-Adapter
PlayerAdapter
ist eine abstrakte Klasse, die den zugrunde liegenden Mediaplayer steuert. Entwickler können die vordefinierte MediaPlayerAdapter
-Implementierung wählen oder eine eigene Implementierung dieser Klasse schreiben.
Die Teile zusammenkleben
Du musst einen Kontrollkleber verwenden, um das Wiedergabefragment mit dem Player zu verbinden. Die Leanback-Bibliothek bietet zwei Arten von Klebstoff:
PlaybackBannerControlGlue
zeichnet die Transportsteuerelemente im Wiedergabefragment im "alten Stil" und platziert sie vor einem undurchsichtigen Hintergrund.PlaybackBannerControlGlue
ersetztPlaybackControlGlue
, das eingestellt wurde.PlaybackTransportControlGlue
verwendet Steuerelemente mit einem neuen Stil mit transparentem Hintergrund.
Wenn deine App Video-Scrubbing unterstützen soll, musst du PlaybackTransportControlGlue
verwenden.
Außerdem müssen Sie einen „Glue Host“ angeben, der den Klebstoff an das Wiedergabefragment bindet, die Transportsteuerelemente in der UI gezeichnet, ihren Status beibehält und Transportsteuerungsereignisse zurück an den Kleber übergibt. Der Host muss dem Wiedergabefragmenttyp entsprechen. Verwenden Sie PlaybackSupportFragmentGlueHost
mit einer PlaybackFragment
und VideoSupportFragmentGlueHost
mit einer VideoFragment
.
Die folgende Abbildung zeigt, wie die einzelnen Elemente einer Leanback-Transportsteuerung zusammenpassen:
Der Code, der Ihre App zusammenfügt, sollte sich in der PlaybackSupportFragment
oder VideoSupportFragment
befinden, die die UI definiert.
Im folgenden Beispiel erstellt die Anwendung eine Instanz von PlaybackTransportControlGlue
, nennt sie playerGlue
, und verbindet ihre VideoSupportFragment
mit einer neu erstellten MediaPlayerAdapter
. Da es sich um ein VideoSupportFragment
handelt, wird mit dem Einrichtungscode setHost()
aufgerufen, um eine VideoSupportFragmentGlueHost
an playerGlue
anzuhängen. Der Code ist in der Klasse enthalten, die die VideoSupportFragment
erweitert.
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)); } }
Mit dem Einrichtungscode wird auch ein PlayerAdapter.Callback
definiert, um Ereignisse aus dem Mediaplayer zu verarbeiten.
UI-Kleber anpassen
Sie können PlaybackBannerControlGlue
und PlaybackTransportControlGlue
anpassen, um PlaybackControlsRow
zu ändern.
Titel und Beschreibung anpassen
Wenn du den Titel und die Beschreibung oben in den Steuerelementen für die Wiedergabe anpassen möchtest, musst du onCreateRowPresenter()
überschreiben:
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; }
Steuerelemente hinzufügen
Der Kontroll-Glue zeigt Steuerelemente für Aktionen in einem PlaybackControlsRow
an.
Die Aktionen in der PlaybackControlsRow
sind zwei Gruppen zugewiesen: primäre Aktionen und sekundäre Aktionen. Die Steuerelemente für die primäre Gruppe werden über der Steuerleiste und die für die sekundäre Gruppe unterhalb der Steuerleiste angezeigt. Anfangs gibt es nur eine einzige primäre Aktion für die Schaltfläche für Wiedergabe/Pause und keine sekundären Aktionen.
Sie können der primären und sekundären Gruppe Aktionen hinzufügen, indem Sie onCreatePrimaryActions()
und onCreateSecondaryActions()
überschreiben.
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); }
Sie müssen onActionClicked()
überschreiben, um die neuen Aktionen zu verarbeiten.
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 Sonderfällen kann es sinnvoll sein, eine eigene PlaybackTransportRowPresenter
zu implementieren, um benutzerdefinierte Steuerelemente zu rendern und mit PlaybackSeekUi
auf Suchaktionen zu reagieren.
Video-Scrubbing
Ob deine App ein VideoSupportFragment
verwendet und das Video-Scrubbing unterstützen möchtest.
Du musst eine Implementierung von PlaybackSeekDataProvider
angeben.
Diese Komponente stellt die Video-Thumbnails bereit, die beim Scrollen verwendet werden.
Sie müssen Ihren eigenen Anbieter implementieren, indem Sie PlaybackSeekDataProvider
erweitern.
Ein Beispiel finden Sie in der
Leanback Showcase App.