Użycie elementów sterujących transportu w funkcji ValueTrack

Biblioteka Leanback na Androidax zawiera nowe elementy sterujące odtwarzaniem, które zwiększają wygodę użytkowników. W aplikacjach wideo elementy sterujące transportem umożliwiają przewijanie filmu za pomocą elementów sterujących do przodu i do tyłu. Podczas przewijania ekranu widać miniatury ułatwiające poruszanie się po filmie.

Biblioteka obejmuje klasy abstrakcyjne, a także gotowe implementacje, które zapewniają programistom bardziej szczegółową kontrolę. Korzystając z gotowych implementacji, możesz szybko stworzyć aplikację oferującą wiele funkcji bez konieczności kodowania. Jeśli potrzebujesz większych możliwości dostosowywania, możesz rozszerzyć dowolne z gotowych komponentów biblioteki.

Sterowanie i odtwarzacz

Biblioteka leanback oddziela interfejs użytkownika od elementów sterujących odtwarzaniem treści wideo. Odbywa się to za pomocą 2 komponentów: fragmentu obsługującego odtwarzanie, który wyświetla elementy sterujące przesyłaniem (i opcjonalnie filmu), oraz adaptera odtwarzacza do umieszczania w nim odtwarzacza.

Fragment odtwarzania

Aktywność w interfejsie aplikacji powinna używać parametru PlaybackSupportFragment lub VideoSupportFragment. Oba typy konfiguracji obejmują ustawienia funkcji leanback transport:

Możesz dostosować ObjectAdapter fragmentu, aby ulepszyć jego interfejs. Na przykład wpisz setAdapter(), aby dodać wiersz „podobne filmy”.

AdapterAdapter

PlayerAdapter to klasa abstrakcyjna, która steruje podstawowym odtwarzaczem. Deweloperzy mogą wybrać gotową implementację MediaPlayerAdapter lub napisać własną implementację.

Sklejanie kawałków

Musisz użyć jakiegoś „kleju kontrolnego”, by połączyć fragment odtwarzania z odtwarzaczem. Biblioteka leanback zawiera 2 rodzaje kleju:

klej do kontroli transportu

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

Musisz też określić „host glue”, który wiąże klej z fragmentem odtwarzania, rysuje w interfejsie użytkownika elementy sterujące transportu i zachowuje ich stan oraz przekazuje zdarzenia sterowania transportem z powrotem do kleju. Host musi pasować do typu fragmentu odtwarzania. Użyj właściwości PlaybackSupportFragmentGlueHost z atrybutem PlaybackFragment, a VideoSupportFragmentGlueHostVideoFragment.

Ilustracja pokazująca, jak elementy systemu leanback transport dopasowują się do siebie:

klej do kontroli transportu

Kod, który łączy aplikację, powinien znajdować się wewnątrz obszaru PlaybackSupportFragment lub VideoSupportFragment, który określa interfejs użytkownika.

W poniższym przykładzie aplikacja tworzy wystąpienie PlaybackTransportControlGlue o nazwie playerGlue i łączy swoje VideoSupportFragment z nowo utworzonym elementem MediaPlayerAdapter. Ponieważ jest to VideoSupportFragment, kod konfiguracji wywołuje metodę 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 określa też element PlayerAdapter.Callback do obsługi zdarzeń z odtwarzacza.

Dostosowywanie kleju 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

Klej kontrolny wyświetla elementy sterujące działaniami w elemencie PlaybackControlsRow.

Działania w PlaybackControlsRow są przypisywane do 2 grup: działań głównych i działań dodatkowych. Elementy sterujące grupy podstawowej znajdują się nad paskiem przewijania, a elementy sterujące grupy dodatkowej – pod paskiem przewijania. Na początku jest tylko jedno działanie główne dla przycisku odtwarzania/wstrzymania. Nie są dostępne żadne działania dodatkowe.

Możesz dodać działania do grupy podstawowej i dodatkowej. W tym celu zastąp 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ć właściwość 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łasne PlaybackTransportRowPresenter, aby renderować niestandardowe elementy sterujące i reagować na działania związane z wyszukiwaniem za pomocą PlaybackSeekUi.

Przewijanie filmu

Jeśli aplikacja korzysta z urządzenia VideoSupportFragment i chcesz obsługiwać przewijanie wideo.

szorowanie

Musisz udostępnić implementację PlaybackSeekDataProvider. Ten komponent dostarcza miniatury filmów używane podczas przewijania. Musisz wdrożyć własnego dostawcę, rozszerzając PlaybackSeekDataProvider. Zobacz ten przykład w aplikacji Polecane Showcase.