Créer un navigateur de catalogue

Une application multimédia exécutée sur un téléviseur doit permettre aux utilisateurs de parcourir ses offres de contenus, de faire une sélection et de commencer à lire du contenu. L'expérience de navigation dans le contenu de ce type d'applications doit être simple, intuitive, visuellement attrayante et engageante.

Un navigateur de catalogue multimédia tend à se composer de plusieurs sections, et chaque section contient une liste de contenus multimédias. Voici quelques exemples de sections d'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 la télévision pour implémenter une interface utilisateur permettant de parcourir de la musique ou des vidéos à partir du catalogue multimédia de votre application.

Créer une fonction composable pour le catalogue

Tout ce qui s'affiche sur un écran est implémenté en tant que fonction composable dans Compose pour la télévision. Commencez par définir une fonction composable pour le navigateur de 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 Media Catalog. La fonction utilise les arguments suivants:

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

Définir des éléments d'interface utilisateur

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

Dans le composable Section, le composant Text est utilisé. 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 que défini dans Material Design en vous reportant à 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 défini comme 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. Ils ont la même surface et aucune différence visuelle entre eux. Vous pouvez mettre en avant certaines d'entre elles avec Carousel.

Le carrousel affiche les informations dans un ensemble d'éléments pouvant glisser, s'estomper ou s'afficher. Vous pouvez utiliser ce composant pour mettre en avant des contenus sélectionnés, comme de nouveaux films ou de nouveaux épisodes de séries TV.

Carousel s'attend à ce que vous spécifiiez au moins le nombre d'éléments du carrousel et la façon de les dessiner. Le premier peut être spécifié avec itemCount. Le second peut être transmis en tant que lambda. Le numéro d'index de l'élément affiché est attribué 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 différée, telle que TvLazyColumn. L'extrait de code 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)
    }
  }
}