Tworzenie przeglądarki katalogu

Aplikacja multimedialna działająca na telewizorze musi umożliwiać użytkownikom przeglądanie oferowanych treści, dokonywanie wyboru i uruchamianie odtwarzania. Przeglądanie treści w przypadku tego typu aplikacji powinno być proste, intuicyjne, atrakcyjne wizualnie i zachęcające do interakcji.

Przeglądarka katalogu multimediów składa się zwykle z kilku sekcji, a każda z nich zawiera listę multimediów. Przykłady sekcji w katalogu multimediów: playlisty, polecane treści, polecane kategorie.

Rysunek 1. Typowy ekran katalogu. Użytkownicy mogą przeglądać dane z katalogu filmów.

Używaj funkcji udostępnianych przez Compose for TV, aby zaimplementować interfejs użytkownika umożliwiający przeglądanie muzyki lub filmów z katalogu multimediów aplikacji.

Tworzenie funkcji typu „composable” dla katalogu

Wszystko, co pojawia się na wyświetlaczu, jest implementowane jako funkcja kompozytowa w Compose for TV. Zacznij od zdefiniowania funkcji składania dla przeglądarki katalogu multimediów:

@Composable
fun CatalogBrowser(
   featuredContentList: List<Movie>,
   sectionList: List<Section>,
   modifier: Modifier = Modifier,
   onItemSelected: (Movie) -> Unit = {},
) {
// ToDo: add implementation
}

CatalogBrowser to funkcja typu „composable” implementująca przeglądarkę katalogu mediów. Funkcja przyjmuje te argumenty:

  • Lista polecanych treści.
  • Lista sekcji.
  • Obiekt Modifier.
  • Funkcja wywołania zwrotnego, która powoduje przejście między ekranami.

Ustawianie elementów interfejsu

Edytor na potrzeby kompozycji na telewizory oferuje listy leniwych zapytań, czyli komponent do wyświetlania dużej liczby elementów (lub listy o nieznanej długości). Aby umieścić sekcje w pionie, użyj funkcji LazyColumn. LazyColumn zawiera blok LazyListScope.() -> Unit, który oferuje DSL do definiowania zawartości elementu. W tym przykładzie każda sekcja jest umieszczona na liście pionowej z przedziałem 16 pikseli między sekcjami:

@Composable
fun CatalogBrowser(
   featuredContentList: List<Movie>,
   sectionList: List<Section>,
   modifier: Modifier = Modifier,
   onItemSelected: (Movie) -> Unit = {},
) {
  LazyColumn(
    modifier = modifier.fillMaxSize(),
    verticalArrangement = Arrangement.spacedBy(16.dp)
  ) {
    items(sectionList) { section ->
      Section(section, onItemSelected = onItemSelected)
    }
  }
}

W tym przykładzie funkcja kompozytowa Section określa sposób wyświetlania sekcji. W następującej funkcji LazyRow pokazujemy, jak ta pozioma wersja funkcji LazyColumn jest używana do definiowania listy poziomej z blokiem LazyListScope.() -> Unit przez wywołanie udostępnionego języka DSL:

@Composable
fun Section(
  section: Section,
  modifier: Modifier = Modifier,
  onItemSelected: (Movie) -> Unit = {},
) {
  Text(
    text = section.title,
    style = MaterialTheme.typography.headlineSmall,
  )
  LazyRow(
     modifier = modifier,
     horizontalArrangement = Arrangement.spacedBy(8.dp)
  ) {
    items(section.movieList){ movie ->
    MovieCard(
         movie = movie,
         onClick = { onItemSelected(movie) }
       )
    }
  }
}

W komponowalnym elemencie Section używany jest komponent Text. Tekst i inne komponenty zdefiniowane w Material Design są dostępne w bibliotece tv-material . Możesz zmienić styl tekstów zdefiniowany w Material Design, odwołując się do obiektu MaterialTheme. Ten obiekt jest też udostępniany przez bibliotekę tv-material. Card należy do biblioteki tv-material. MovieCard określa, jak dane każdego filmu są renderowane w katalogu zdefiniowanym w tym fragmencie kodu:

@Composable
fun MovieCard(
   movie: Movie,
   modifier: Modifier = Modifier,
   onClick: () -> Unit = {}
) {
   Card(modifier = modifier, onClick = onClick){
    AsyncImage(
       model = movie.thumbnailUrl,
       contentDescription = movie.title,
     )
   }
}

W przypadku opisanego wcześniej przykładu wszystkie filmy są wyświetlane w takim samym stopniu. Mają ten sam obszar i nie różnią się wizualnie. Niektóre z nich możesz wyróżnić za pomocą Carousel.

Karuzela wyświetla informacje w układzie elementów, które mogą się przesuwać, zanikać lub przesuwać w pole widzenia. Za pomocą tego komponentu możesz wyróżnić polecane treści, takie jak nowo dostępne filmy lub nowe odcinki programów telewizyjnych.

Carousel oczekuje, że określisz co najmniej liczbę elementów w karuzeli oraz sposób ich rysowania. Pierwszy z nich można określić za pomocą parametru itemCount. Drugi może być przekazywany jako funkcja lambda. Lambda otrzymuje numer indeksu wyświetlanego elementu. Wyświetlany element możesz określić za pomocą podanej wartości indeksu:

@Composable
function FeaturedCarousel(
  featuredContentList: List<Movie>,
  modifier: Modifier = Modifier,
) {
  Carousel(
    itemCount = featuredContentList.size,
    modifier = modifier,
  ) { index ->
    val content = featuredContentList[index]
    Box {
      AsyncImage(
        model = content.backgroundImageUrl,
        contentDescription = content.description,
        placeholder = painterResource(
          id = R.drawable.placeholder
        ),
        contentScale = ContentScale.Crop,
        modifier = Modifier.fillMaxSize()
      )
      Text(text = content.title)
    }
  }
}

Carousel może być elementem listy leniwej, np. TvLazyColumn. Poniższy fragment kodu pokazuje komponent FeaturedCarousel na wierzchu wszystkich komponentów Section:

@Composable
fun CatalogBrowser(
   featuredContentList: List<Movie>,
   sectionList: List<Section>,
   modifier: Modifier = Modifier,
   onItemSelected: (Movie) -> Unit = {},
) {
  TvLazyColumn(
    modifier = modifier.fillMaxSize(),
    verticalArrangement = Arrangement.spacedBy(16.dp)
  ) {

    item {
      FeaturedCarousel(featuredContentList)
    }

    items(sectionList) { section ->
      Section(section, onItemSelected = onItemSelected)
    }
  }
}