Créer un navigateur de catalogue

Une application multimédia qui s'exécute sur un téléviseur doit permettre aux utilisateurs de parcourir son offre de contenu, de faire une sélection et de lancer la lecture du contenu. L'expérience de navigation dans le contenu des applications de ce type doit être simple, intuitive, visuellement agréable et engageante.

Un navigateur de catalogue multimédia se compose généralement de plusieurs sections, chacune contenant une liste de contenus multimédias. Voici quelques exemples de sections dans un catalogue multimédia : playlists, contenus mis en avant, catégories recommandées.

Figure 1. Écran de catalogue type. Les utilisateurs peuvent parcourir les données du catalogue vidéo.

Utilisez les fonctions fournies par Compose pour TV afin d'implémenter une interface utilisateur permettant de parcourir la musique ou les vidéos du catalogue multimédia de votre application.

Créer une fonction composable pour le catalogue

Tout ce qui s'affiche à l'écran est implémenté en tant que fonction composable dans Compose pour TV. Commencez par définir une fonction composable pour le navigateur du catalogue multimédia :

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

CatalogBrowser est la fonction composable qui implémente votre navigateur de catalogue multimédia. La fonction utilise les arguments suivants :

  • Liste des contenus mis en avant.
  • Liste des sections.
  • Objet Modifier.
  • Une fonction de rappel qui déclenche une transition d'écran.

Définir des éléments d'UI

Compose pour TV propose des listes "lazy", un composant permettant d'afficher un grand nombre d'éléments (ou une liste d'une longueur indéterminée). Appelez LazyColumn pour placer les sections verticalement. LazyColumn fournit un bloc LazyListScope.() -> Unit, qui propose un DSL pour définir le contenu des éléments. Dans l'exemple suivant, chaque section est placée dans une liste verticale avec un espace de 16 dp entre les sections :

@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)
    }
  }
}

Dans l'exemple, la fonction composable Section définit la façon d'afficher les sections. Dans la fonction suivante, LazyRow montre comment cette version horizontale de LazyColumn est également utilisée pour définir une liste horizontale avec un bloc LazyListScope.() -> Unit en appelant le DSL fourni :

@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) }
       )
    }
  }
}

Le composable Section utilise le composant Text. Le texte et les autres composants définis dans Material Design sont proposés dans la bibliothèque tv-material . Vous pouvez modifier le style des textes tel qu'il est défini dans Material Design en vous référant à l'objet MaterialTheme. Cet objet est également fourni par la bibliothèque tv-material. Card fait partie de la bibliothèque tv-material. MovieCard définit la façon dont chaque donnée de film est affichée dans le catalogue, comme indiqué dans l'extrait de code suivant :

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

Dans l'exemple décrit précédemment, tous les films sont affichés de manière égale. Elles ont la même superficie et ne présentent aucune différence visuelle. Vous pouvez en mettre en évidence certains avec Carousel.

Le carrousel affiche les informations dans un ensemble d'éléments qui peuvent glisser, s'estomper ou se déplacer dans la vue. Vous utilisez le composant pour mettre en avant des contenus, comme des films récemment disponibles ou de nouveaux épisodes de séries TV.

Carousel s'attend à ce que vous spécifiiez au moins le nombre d'éléments que contient le carrousel et la manière de dessiner chaque élément. Le premier peut être spécifié avec itemCount. La seconde peut être transmise en tant que lambda. Le numéro d'index de l'élément affiché est transmis au lambda. Vous pouvez déterminer l'élément affiché avec la valeur d'index donnée :

@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 peut être un élément d'une liste paresseuse, comme TvLazyColumn. L'extrait suivant montre le composable FeaturedCarousel au-dessus de tous les composables 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)
    }
  }
}