Korzystanie z ustawień transportu

Ulepszaj dzięki funkcji tworzenia wiadomości
Dzięki Jetpack Compose na system operacyjny Android TV możesz tworzyć atrakcyjne interfejsy użytkownika przy użyciu minimalnej ilości pisania.

Zestaw narzędzi interfejsu Leanback zawiera elementy sterujące odtwarzaniem zwiększające wygodę użytkowników. W przypadku aplikacji wideo elementy sterujące transportem umożliwiają przewijanie filmu za pomocą elementów sterujących do przodu i do tyłu. Podczas przewijania wyświetlacza pojawiają się miniatury ułatwiające poruszanie się po filmie.

Biblioteka zawiera klasy abstrakcyjne, a także gotowe, gotowe implementacje, które dają programistom bardziej szczegółową kontrolę. Korzystając z gotowych implementacji, możesz szybko utworzyć aplikację z wieloma funkcjami bez konieczności kodowania. Jeśli potrzebujesz większych możliwości dostosowywania, możesz rozszerzyć dowolny z gotowych komponentów biblioteki.

Elementy sterujące i odtwarzacz

Zestaw narzędzi interfejsu Leanback oddziela interfejs sterowania transportem od odtwarzacza odtwarzającego wideo. Składa się on z 2 komponentów: fragmentu obsługi odtwarzania służącego do wyświetlania elementów sterujących przesyłaniem (i opcjonalnie filmu) oraz adaptera odtwarzacza, który pozwala umieścić odtwarzacz.

Fragment odtwarzania

Aktywność w interfejsie aplikacji powinna zawierać PlaybackSupportFragment lub VideoSupportFragment. Oba zawierają elementy sterujące przenoszeniem Leanback:

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

PlayerAdapter

PlayerAdapter to klasa abstrakcyjna, która kontroluje działanie odtwarzacza. Deweloperzy mogą wybrać gotową implementację MediaPlayerAdapter lub napisać własną implementację tej klasy.

Sklejanie elementów

Aby połączyć fragment odtwarzania z odtwarzaczem, musisz użyć „kleju kontrolującego”. Biblioteka Leanback zawiera 2 rodzaje kleju:

leanback transporter glue

Jeśli chcesz, by aplikacja obsługiwała scrubbing wideo, musisz użyć polecenia PlaybackTransportControlGlue.

Musisz też określić „hosta glue”, który powiąże klej z fragmentem odtwarzania, rysuje elementy sterujące transportu w interfejsie użytkownika, zachowuje swój stan oraz przekazuje zdarzenia sterujące transportu z powrotem do kleju. Host musi pasować do typu fragmentu przy odtwarzaniu. Używaj PlaybackSupportFragmentGlueHost z PlaybackFragment i VideoSupportFragmentGlueHost z VideoFragment.

Oto ilustracja, która obrazuje, jak elementy sterujące transportu w ramach funkcji Leanback łączą się ze sobą:

leanback transporter glue

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

W poniższym przykładzie aplikacja tworzy instancję PlaybackTransportControlGlue, nazywając ją playerGlue, a potem łączy 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ż element PlayerAdapter.Callback do obsługi zdarzeń z odtwarzacza.

Dostosowywanie kleju do interfejsu

Możesz dostosować PlaybackBannerControlGlue i PlaybackTransportControlGlue, aby zmienić PlaybackControlsRow.

Dostosowywanie tytułu i opisu

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

Element sterujący typu glue wyświetla elementy sterujące działaniami w elemencie PlaybackControlsRow.

Działania w obiekcie PlaybackControlsRow są przypisane do 2 grup: działania główne i działania dodatkowe. Elementy sterujące grupy podstawowej są widoczne nad paskiem przewijania, a elementy sterujące grupy dodatkowej – pod paskiem przewijania. Początkowo przycisk odtwarzania/wstrzymywania jest tylko 1 działaniem głównym i nie ma działań dodatkowych.

Możesz dodać działania do grup głównych i dodatkowych, zastępując parametry onCreatePrimaryActions() i 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ć parametr 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 zastosować własne PlaybackTransportRowPresenter, aby renderować niestandardowe elementy sterujące i reagować na działania wyszukiwania za pomocą interfejsu PlaybackSeekUi.

Czyszczenie filmów

Jeśli Twoja aplikacja używa interfejsu VideoSupportFragment i chcesz obsługiwać przewijanie wideo.

szorowanie

Musisz udostępnić implementację interfejsu PlaybackSeekDataProvider. Ten komponent udostępnia miniatury filmów używane podczas przewijania. Musisz wdrożyć własnego dostawcę przez rozszerzenie PlaybackSeekDataProvider. Zobacz ten przykład w aplikacji Leanback Showcase.