Tworzenie przeglądarki katalogu

Aplikacja multimedialna działająca na telewizorze musi umożliwiać użytkownikom przeglądanie oferowanych treści, wybieranie ich i odtwarzanie. 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 składana 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 uruchamia przejście między ekranami.

Ustawianie elementów interfejsu

Edytor na potrzeby kompozycji na telewizory oferuje listy leniwych zasobów, 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 udostępnia 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 pojawiać na ekranie. 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 wyświetlania. 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. Ten 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)
    }
  }
}