Korzystanie z ustawień transportu

Tworzenie lepszych aplikacji za pomocą Compose
Twórz piękne interfejsy z minimalną ilością kodu za pomocą Jetpack Compose na Androida TV OS.

Zestaw narzędzi interfejsu Leanback zawiera elementy sterujące odtwarzaniem, które zapewniają lepsze wrażenia użytkownika. W przypadku aplikacji wideo elementy sterujące transportem obsługują przewijanie wideo za pomocą przycisków do przodu i do tyłu. Podczas przewijania wyświetlają się miniatury, które ułatwiają poruszanie się po filmie.

Biblioteka zawiera klasy abstrakcyjne, a także gotowe implementacje, które zapewniają programistom większą kontrolę. Korzystając z gotowych implementacji, możesz szybko utworzyć aplikację z wieloma funkcjami bez konieczności pisania dużej ilości kodu. Jeśli potrzebujesz większej możliwości dostosowania, możesz rozszerzyć dowolny z gotowych komponentów biblioteki.

Elementy sterujące i odtwarzacz

Zestaw narzędzi interfejsu Leanback oddziela interfejs elementów sterujących odtwarzaniem od odtwarzacza, który odtwarza wideo. Osiąga się to za pomocą 2 komponentów: fragmentu obsługi odtwarzania do wyświetlania elementów sterujących odtwarzaniem (i opcjonalnie filmu) oraz adaptera odtwarzacza do enkapsulacji odtwarzacza multimediów.

Odtwórz fragment

Aktywność interfejsu aplikacji powinna używać elementu PlaybackSupportFragment lub VideoSupportFragment. Oba zawierają elementy sterujące odtwarzaniem w trybie leanback:

Możesz dostosować fragmentObjectAdapter, aby ulepszyć interfejs. Na przykład użyj setAdapter() aby dodać wiersz „Podobne filmy”.

PlayerAdapter

PlayerAdapter to klasa abstrakcyjna, która kontroluje bazowy odtwarzacz multimediów. Programiści mogą wybrać gotową implementację MediaPlayerAdapter lub napisać własną implementację tej klasy.

Łączenie elementów

Aby połączyć fragment odtwarzania z odtwarzaczem, musisz użyć „kleju sterującego”. Biblioteka leanback udostępnia 2 rodzaje „kleju”:

leanback transport control glue

Jeśli chcesz, aby aplikacja obsługiwała przewijanie wideo, musisz użyć PlaybackTransportControlGlue.

Musisz też określić „hosta łączącego”, który łączy element z fragmentem odtwarzania, rysuje elementy sterujące odtwarzaniem w interfejsie i utrzymuje ich stan oraz przekazuje zdarzenia sterowania odtwarzaniem z powrotem do elementu. Host musi być zgodny z typem fragmentu odtwarzania. Użyj właściwości PlaybackSupportFragmentGlueHost z właściwością PlaybackFragment oraz właściwości VideoSupportFragmentGlueHost z właściwością VideoFragment.

Ilustracja pokazująca, jak elementy sterowania odtwarzaniem w trybie pasywnym łączą się ze sobą:

leanback transport control glue

Kod, który łączy aplikację, powinien znajdować się w elemencie PlaybackSupportFragment lub VideoSupportFragment definiującym interfejs.

W tym przykładzie aplikacja tworzy instancjęPlaybackTransportControlGlue, nadaje jej nazwę playerGlue i łączy jej VideoSupportFragment z nowo utworzonym MediaPlayerAdapter. Ponieważ jest to VideoSupportFragment, kod konfiguracji wywołuje setHost(), aby dołączyć VideoSupportFragmentGlueHost do playerGlue. Kod jest zawarty w klasie, która rozszerza 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));
  }
}

Pamiętaj, że kod konfiguracji definiuje też PlayerAdapter.Callback do obsługi zdarzeń z odtwarzacza multimediów.

Dostosowywanie kodu interfejsu

Możesz dostosować parametry PlaybackBannerControlGluePlaybackTransportControlGlue, aby zmienić PlaybackControlsRow.

Dostosowywanie tytułu i opisu

Aby dostosować tytuł i opis u góry elementów sterujących odtwarzaniem, zastąp funkcję 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;
}

Dodawanie elementów sterujących

W przypadku działań w PlaybackControlsRow wyświetla się pasek sterowania.

Działania w PlaybackControlsRow są przypisane do 2 grup: działań głównychdziałań dodatkowych. Elementy sterujące grupy głównej znajdują się nad paskiem przewijania, a elementy sterujące grupy dodatkowej – pod nim. Początkowo przycisk odtwarzania/wstrzymywania ma tylko jedno działanie podstawowe i nie ma działań dodatkowych.

Działania możesz dodawać do grup głównych i dodatkowych, zastępując wartości onCreatePrimaryActions()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);
}

Aby obsługiwać nowe działania, musisz zastąpić metodę onActionClicked().

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.
}

W szczególnych przypadkach możesz zaimplementować własny interfejs PlaybackTransportRowPresenter do renderowania niestandardowych elementów sterujących i reagowania na działania związane z przewijaniem za pomocą interfejsu PlaybackSeekUi.

Przewijanie filmu

Jeśli Twoja aplikacja korzysta z VideoSupportFragment i chcesz obsługiwać przewijanie filmów.

szorowanie

Musisz podać implementację PlaybackSeekDataProvider. Ten komponent zawiera miniatury filmów używane podczas przewijania. Musisz wdrożyć własnego dostawcę, rozszerzając klasę PlaybackSeekDataProvider. Przykład znajdziesz w  aplikacji Leanback Showcase.