Steuerelemente für die Übertragung verwenden

Mit Compose bessere Apps entwickeln
Mit Jetpack Compose für Android TV OS lassen sich mit minimalem Code beeindruckende Benutzeroberflächen erstellen.

Das Leanback-UI-Toolkit verfügt über Steuerelemente für die Wiedergabe, die eine verbesserte User Experience ausmacht. Bei Video-Apps unterstützen die Transportsteuerungen das Überspringen von Videoinhalten mit den Steuerelementen „Vorwärts“ und „Rückwärts“. Während des Scrubbings werden auf dem Display Thumbnails angezeigt, die die Navigation durch das Video erleichtern.

Die Bibliothek enthält abstrakte Klassen sowie vorgefertigte, sofort einsatzbereite Implementierungen, die Entwicklern eine detailliertere Kontrolle bieten. Vordefinierte 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.

Steuerelemente und Player

Das Leanback-UI-Toolkit trennt die UI für Transportsteuerelemente von der dem 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 zum kapseln eines Mediaplayers.

Wiedergabefragment

Für die UI-Aktivität Ihrer App sollte ein PlaybackSupportFragment oder VideoSupportFragment. Beide enthalten die Steuerelemente für den Leanback-Transport:

Sie können die ObjectAdapter um die Benutzeroberfläche zu verbessern. Verwenden Sie beispielsweise setAdapter() um ein ähnliches Video Zeile.

Player-Adapter

PlayerAdapter ist eine abstrakte Klasse, die den zugrunde liegenden Mediaplayer steuert. Entwickler können die vordefinierte MediaPlayerAdapter-Implementierung auswählen oder eine eigene Implementierung dieser Klasse schreiben.

Die Teile zusammenkleben

Du musst „Kontrollkleber“ verwenden zum Verbinden des Wiedergabefragments für den Player. Die Leanback-Bibliothek bietet zwei Arten von Klebemitteln:

leanback transport control glue

Wenn deine App Video-Scrubbing unterstützen soll, musst du PlaybackTransportControlGlue

Sie müssen auch einen „Glue Host“ angeben das bindet den Klebstoff an die Wiedergabe fragmentiert, zeichnet die Transportsteuerelemente in der Benutzeroberfläche auf und behält ihren Status bei Transportsteuerungsereignisse zurück an den Kleber. Der Host muss dem Wiedergabefragmenttyp entsprechen. Verwende PlaybackSupportFragmentGlueHost mit PlaybackFragment und VideoSupportFragmentGlueHost mit VideoFragment.

Hier ist eine Abbildung, die zeigt, wie die einzelnen Elemente einer zusammenpassen:

Leanback Transport Control Kleber

Der Code, der Ihre App zusammenhält, sollte sich in der PlaybackSupportFragment oder VideoSupportFragment befinden, die die Benutzeroberfläche definiert.

Im folgenden Beispiel erstellt die App eine Instanz von PlaybackTransportControlGlue, benennt sie playerGlue und verbindet ihre VideoSupportFragment mit einer neu erstellten MediaPlayerAdapter. Da es sich um ein VideoSupportFragment handelt, ruft der Einrichtungscode setHost() auf, um playerGlue eine VideoSupportFragmentGlueHost anzuhängen. Der Code ist in der Klasse enthalten, 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));
  }
}

Im Einrichtungscode ist auch ein PlayerAdapter.Callback definiert, um Ereignisse aus im Mediaplayer an.

UI-Kleber anpassen

Sie können anpassen PlaybackBannerControlGlue und PlaybackTransportControlGlue zum Ändern der PlaybackControlsRow

Titel und Beschreibung anpassen

Wenn du den Titel und die Beschreibung oben in den Wiedergabesteuerungen anpassen möchtest, überschreibe 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;
}

Steuerelemente hinzufügen

Der Steuerelement-Glue zeigt Steuerelemente für Aktionen in einer PlaybackControlsRow an.

Die Aktionen in PlaybackControlsRow sind zwei Gruppen zugewiesen: primäre Aktionen und sekundär. Aktionen. Die Steuerelemente für die primäre Gruppe werden über der Suchleiste angezeigt und die Steuerelemente für die sekundäre Gruppe werden unterhalb der Suchleiste angezeigt. Anfangs gibt es nur eine 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().

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 bestimmten Fällen kann es sinnvoll sein, eine eigene PlaybackTransportRowPresenter zu implementieren, um benutzerdefinierte Steuerelemente zu rendern und mit der PlaybackSeekUi auf Suchaktionen zu reagieren.

Video-Scrubbing

Ob deine App ein VideoSupportFragment verwendet und das Video-Scrubbing unterstützen möchtest.

scheuern

Sie müssen eine Implementierung von PlaybackSeekDataProvider bereitstellen. Diese Komponente enthält die Video-Thumbnails, die beim Scrollen verwendet werden. Sie müssen Ihren eigenen Anbieter implementieren, PlaybackSeekDataProvider Sehen Sie sich das Beispiel in der Leanback Showcase App an.