Steuerelemente für die Übertragung verwenden

Bessere Apps mit Compose entwickeln
Mit Jetpack Compose für Android TV OS können Sie ansprechende Benutzeroberflächen mit minimalem Code erstellen.

Das Leanback UI-Toolkit enthält Wiedergabesteuerelemente, die die Nutzerfreundlichkeit verbessern. Bei Video-Apps unterstützen die Transportsteuerelemente das Scrubbing von Videos mit den Steuerelementen für Vorwärts- und Rückwärtsspulen. Während des Scrubbings werden Thumbnails angezeigt, die die Navigation durch das Video erleichtern.

Die Bibliothek enthält abstrakte Klassen sowie vorgefertigte Implementierungen, die Entwicklern eine detailliertere Steuerung ermöglichen. Mit den vorgefertigten Implementierungen können Sie schnell eine funktionsreiche App ohne viel Code erstellen. Wenn Sie weitere Anpassungen benötigen, können Sie jede der vorgefertigten Komponenten der Bibliothek erweitern.

Steuerelemente und Player

Das Leanback UI-Toolkit trennt die Benutzeroberfläche der Transportsteuerelemente vom Player, der das Video wiedergibt. Dies wird mit zwei Komponenten erreicht: einem Wiedergabe-Support-Fragment zum Anzeigen der Transportsteuerelemente (und optional des Videos) und einem Player-Adapter zum Kapseln eines Media-Players.

Wiedergabe-Fragment

Die UI-Aktivität Ihrer App sollte ein PlaybackSupportFragment oder ein VideoSupportFragment verwenden. Beide enthalten die Leanback-Transportsteuerelemente:

Sie können den ObjectAdapter eines Fragments anpassen, um die Benutzeroberfläche zu verbessern. Verwenden Sie beispielsweise setAdapter(), um eine Zeile mit ähnlichen Videos hinzuzufügen.

PlayerAdapter

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

Teile zusammenfügen

Sie müssen einen „Steuerkleber“ verwenden, um das Wiedergabe-Fragment mit dem Player zu verbinden. Die Leanback-Bibliothek bietet zwei Arten von Klebern:

Leanback-Transportsteuerelemente

Wenn Ihre App das Scrubbing von Videos unterstützen soll, müssen Sie PlaybackTransportControlGlue verwenden.

Sie müssen auch einen „Kleber-Host“ angeben, der den Kleber an das Wiedergabe-Fragment bindet, die Transportsteuerelemente in der Benutzeroberfläche zeichnet und ihren Status beibehält und Ereignisse der Transportsteuerelemente an den Kleber zurückgibt. Der Host muss dem Typ des Wiedergabe-Fragments entsprechen. Verwenden Sie PlaybackSupportFragmentGlueHost mit einem PlaybackFragment und VideoSupportFragmentGlueHost mit einem VideoFragment.

Hier sehen Sie eine Abbildung, wie die Teile eines Leanback-Transportsteuerelements zusammenpassen:

Leanback-Transportsteuerelement-Glue

Der Code, der Ihre App zusammenfügt, sollte sich im PlaybackSupportFragment oder VideoSupportFragment befinden, das die Benutzeroberfläche definiert.

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

Der Einrichtungscode definiert auch einen PlayerAdapter.Callback, um Ereignisse vom Media-Player zu verarbeiten.

UI-Kleber anpassen

Sie können PlaybackBannerControlGlue und PlaybackTransportControlGlue anpassen, um die PlaybackControlsRow zu ändern.

Titel und Beschreibung anpassen

Wenn Sie den Titel und die Beschreibung oben in den Wiedergabesteuerelementen anpassen möchten, überschreiben Sie 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 Steuerkleber zeigt Steuerelemente für Aktionen in einer PlaybackControlsRow an.

Die Aktionen in der PlaybackControlsRow sind zwei Gruppen zugewiesen: primäre Aktionen und sekundäre Aktionen. Steuerelemente für die primäre Gruppe werden über der Suchleiste und Steuerelemente für die sekundäre Gruppe unter der Suchleiste angezeigt. Anfangs gibt es nur eine primäre Aktion für die Schaltfläche „Wiedergabe/Pause“ und keine sekundären Aktionen.

Sie können Aktionen zu den primären und sekundären Gruppen 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 besonderen Fällen möchten Sie möglicherweise einen eigenen PlaybackTransportRowPresenter implementieren, um benutzerdefinierte Steuerelemente zu rendern und mit PlaybackSeekUi auf Suchaktionen zu reagieren.

Video-Scrubbing

Wenn Ihre App ein VideoSupportFragment verwendet und Sie das Scrubbing von Videos unterstützen möchten.

scheuern

Sie müssen eine Implementierung von PlaybackSeekDataProvider bereitstellen. Diese Komponente stellt die Video-Thumbnails bereit, die beim Scrollen verwendet werden. Sie müssen einen eigenen Anbieter implementieren, indem Sie PlaybackSeekDataProvider erweitern. Ein Beispiel finden Sie in der Leanback Showcase-App. .