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, d'en faire une sélection et de commencer à lire du contenu. L'expérience de navigation dans le contenu des applications de ce type doit être simple et intuitive, et visuellement agréable et attrayante.

Cette section explique comment utiliser les fonctions fournies par Compose pour la télévision afin d'implémenter une interface utilisateur permettant de parcourir des titres ou des vidéos du catalogue multimédia de votre application.

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

Un navigateur de catalogue multimédia se compose généralement de plusieurs sections, chacune associée à une liste de contenus multimédias. Voici quelques exemples de sections : playlists, sélection de contenus, catégories recommandées

Créer une fonction composable pour le catalogue

Tout ce qui s'affiche sur un écran est implémenté en tant que fonction modulable dans Compose pour la télévision. Vous allez commencer par définir une fonction composable pour le navigateur de catalogue multimédia à l'aide de l'extrait suivant:

@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 de contenus sélectionnés.
  • Liste des sections.
  • Un objet Modifier.
  • Une fonction de rappel, qui déclenche une transition d'écran

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

Compose pour la télévision propose des listes différées, un composant permettant d'afficher un grand nombre d'éléments (ou une liste de longueur inconnue). Vous allez appeler TvLazyColumn pour placer les sections verticalement. TvLazyColumn fournit un bloc TvLazyListScope.() -> Unit, qui propose un DSL pour définir le contenu de l'élément. Dans l'exemple suivant, chaque section est placée dans une liste verticale avec un écart de 16 dp entre les sections.

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

Dans l'exemple, la fonction composable Section définit comment afficher les sections. Dans la fonction suivante, TvLazyRow montre comment cette version horizontale de TvLazyColumn est également utilisée pour définir une liste horizontale avec un bloc TvLazyListScope.() -> 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,
  )
  TvLazyRow(
     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. MovieCard définit la manière dont les données de chaque film sont affichées dans le catalogue défini comme l'extrait suivant. Card fait également partie de la bibliothèque tv-material.

@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 zone, sans différence visuelle entre eux. Vous pouvez mettre en surbrillance certains d'entre eux avec Carousel.

Le carrousel affiche les informations sous la forme d'un ensemble d'éléments qui peuvent faire glisser, fondre ou afficher. Ce composant vous permet de mettre en avant une sélection de contenus, comme de nouveaux films disponibles ou de nouveaux épisodes de programmes télévisés.

Carousel s'attend à ce que vous spécifiiez au moins le nombre d'éléments présents dans le carrousel et la manière de dessiner chaque élément. 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 faire partie d'une liste différée, comme 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)
    }
  }
}