1. Avant de commencer
Compose pour la télévision est le dernier framework d'UI permettant de développer des applications exécutées sur Android TV. Il offre tous les avantages de Jetpack Compose pour les applis TV afin de vous permettre de créer plus facilement des interfaces utilisateur attrayantes et fonctionnelles. Voici quelques avantages spécifiques de Compose pour la télévision :
- Flexibilité : Compose permet de créer n'importe quel type d'UI, qu'il s'agisse de mises en page simples ou d'animations complexes. Les composants sont prêts à l'emploi, mais vous pouvez aussi les personnaliser et les façons selon les besoins de votre application.
- Développement accéléré et simplifié : Compose étant compatible avec le code existant, les développeurs peuvent créer des applications avec moins de code.
- Intuitivité : Compose utilise une syntaxe déclarative qui permet de modifier votre UI de manière intuitive, mais aussi de déboguer, comprendre et examiner votre code.
Parmi les cas d'utilisation courants des applications TV, on retrouve la consommation de contenus multimédias. Les utilisateurs parcourent les catalogues de contenus et sélectionnent ceux qu'ils souhaitent regarder. Il peut s'agir d'un film, d'une série TV ou d'un podcast. Après avoir sélectionné un contenu, l'utilisateur peut souhaiter en savoir plus sur celui-ci, par exemple par le biais d'une brève description, de la durée de la lecture et du nom des créateurs. Dans cet atelier de programmation, vous découvrirez comment implémenter un navigateur de catalogue et un écran d'informations avec Compose pour la télévision.
Conditions préalables
- Connaissances de la syntaxe du langage Kotlin, y compris les lambdas.
- Vous disposez d'une expérience de base avec Compose. Si vous ne connaissez pas Compose, suivez l'atelier de programmation Principes de base de Jetpack Compose.
- Vous disposez de connaissances de base sur les composables et les modificateurs.
Objectif de l'atelier
- Une application de lecteur vidéo avec un navigateur de catalogue et un écran d'informations
- Un navigateur de catalogue affichant une liste de vidéos que les utilisateurs peuvent choisir. Il se présente comme suit :
- Un écran d'informations affichant les métadonnées de la vidéo sélectionnée, comme le titre, la description et la durée. Il se présente comme suit :
Ce dont vous avez besoin
- La dernière version d'Android Studio
2. Configuration
Afin d'obtenir le code contenant la thématisation et la configuration de base pour cet atelier de programmation, effectuez l'une des opérations suivantes :
- Clonez le code de ce dépôt GitHub :
$ git clone https://github.com/android/tv-codelabs.git
La branche main
contient le code de démarrage et la branche solution
contient le code de solution.
- Téléchargez le fichier
main.zip
, qui contient le code de démarrage, et le fichiersolution.zip
, qui contient le code de solution.
Maintenant que vous avez téléchargé le code, ouvrez le projet IntroductionToComposeForTV dans Android Studio. Vous êtes prêt à commencer.
3. Implémenter l'écran du navigateur de catalogue
Grâce au navigateur, les utilisateurs peuvent parcourir les catalogues de films. Vous allez implémenter le navigateur de catalogue en tant que fonction Composable
. La fonction Composable
CatalogBrowser
se trouve dans le fichier CatalogBrowser.kt
. Vous allez implémenter le navigateur de catalogue dans cette fonction Composable
.
Le code de démarrage contient une classe ViewModel appelée CatalogBrowserViewModel
. Elle comporte plusieurs attributs et méthodes pour récupérer des objets Movie
décrivant le contenu du film. Vous allez implémenter un navigateur de catalogue en récupérant des objets Movie
.
CatalogBrowser.kt
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.tv.material3.ExperimentalTvMaterial3Api
import com.example.tvcomposeintroduction.data.Movie
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = viewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
}
Afficher les noms des catégories
Vous pouvez accéder à une liste de catégories avec l'attribut catalogBrowserViewModel.categoryList
. il s'agit du flux d'une liste Category
. Le flux est collecté en tant qu'objet Compose State
en appelant la méthode collectAsState
. Un objet Category
possède un attribut name
. Il s'agit d'une valeur String
correspondant au nom de la catégorie.
Pour afficher les noms des catégories, procédez comme suit :
- Dans Android Studio, ouvrez le fichier
CatalogBrowser.kt
du code de démarrage, puis ajoutez une fonctionComposable
TvLazyColumn
à la fonctionComposable
CatalogBrowser
. - Appelez la méthode
catalogBrowserViewModel.categoryList.collectAsState()
pour collecter le flux en tant qu'objetState
. - Déclarez
categoryList
en tant que propriété déléguée de l'objetState
créé à l'étape précédente. - Appelez la fonction
items
avec la variablecategoryList
en tant que paramètre. - Appelez la fonction
Composable
Text
avec le nom de la catégorie comme paramètre transmis en tant qu'argument du lambda.
CatalogBrowser.kt
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.tv.foundation.lazy.list.TvLazyColumn
import androidx.tv.foundation.lazy.list.items
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
import com.example.tvcomposeintroduction.data.Movie
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = viewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsState()
TvLazyColumn(modifier = modifier) {
items(categoryList) { category ->
Text(text = category.name)
}
}
}
Afficher la liste de contenu pour chaque catégorie
Un objet Category
possède un autre attribut appelé movieList
. Il s'agit d'une liste d'objets Movie
correspondant aux films qui appartiennent à la catégorie.
Pour afficher la liste de contenu de chaque catégorie, procédez comme suit :
- Ajoutez la fonction
Composable
TvLazyRow
, puis transmettez-lui un lambda. - Dans le lambda, appelez la fonction
items
aveccategory
etla valeur d'attributmovieList
, puis transmettez-lui un lambda. - Dans le lambda transmis à la fonction
items
, appelez la fonctionComposable
MovieCard
avec un objetMovie
.
CatalogBrowser.kt
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.tv.foundation.lazy.list.TvLazyColumn
import androidx.tv.foundation.lazy.list.TvLazyRow
import androidx.tv.foundation.lazy.list.items
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
import com.example.tvcomposeintroduction.data.Movie
import com.example.tvcomposeintroduction.ui.components.MovieCard
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = viewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsState()
TvLazyColumn(modifier = modifier) {
items(categoryList) { category ->
Text(text = category.name)
TvLazyRow {
items(category.movieList) {movie ->
MovieCard(movie = movie)
}
}
}
}
}
Facultatif : Ajuster la mise en page
- Pour définir l'écart entre les catégories, transmettez un objet
Arrangement
à la fonctionComposable
TvLazyColumn
avec le paramètreverticalArrangement
. L'objetArrangement
est créé en appelant la méthodeArrangement#spacedBy
. - Pour définir l'écart entre les fiches de films, transmettez un objet
Arrangement
à la fonctionComposable
TvLazyRow
avec le paramètrehorizontalArrangement
. - Pour définir un retrait au niveau de la colonne, transmettez un objet
PaddingValue
avec le paramètrecontentPadding
.
CatalogBrowser.kt
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.tv.foundation.lazy.list.TvLazyColumn
import androidx.tv.foundation.lazy.list.TvLazyRow
import androidx.tv.foundation.lazy.list.items
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
import com.example.tvcomposeintroduction.data.Movie
import com.example.tvcomposeintroduction.ui.components.MovieCard
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = viewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsState()
TvLazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
items(categoryList) { category ->
Text(text = category.name)
TvLazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(category.movieList) { movie ->
MovieCard(movie = movie)
}
}
}
}
}
4. Implémenter l'écran d'informations
L'écran d'informations présente les détails du film sélectionné. Le fichier Details.kt
contient une fonction Composable
Details
. Vous allez ajouter du code à cette fonction pour implémenter l'écran d'informations.
Details.kt
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.tv.material3.ExperimentalTvMaterial3Api
import com.example.tvcomposeintroduction.data.Movie
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun Details(movie: Movie, modifier: Modifier = Modifier) {
}
Afficher le titre, le nom du studio et la description du film
Un objet Movie
possède les trois attributs de chaîne de caractères suivants comme métadonnées du film :
title
: titre du filmstudio
: nom du studio qui a produit le filmdescription
: bref résumé du film
Pour afficher ces métadonnées sur l'écran d'informations, procédez comme suit :
- Ajoutez une fonction
Composable
Column
, puis définissez une marge verticale de 32 dp et une marge horizontale de 48 dp autour de la colonne avec l'objetModifier
créé par la méthodeModifier.padding
. - Ajoutez une fonction
Composable
Text
pour afficher le titre du film. - Ajoutez une fonction
Composable
Text
pour afficher le nom du studio. - Ajoutez une fonction
Composable
Text
pour afficher la description du film.
Details.kt
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
import com.example.tvcomposeintroduction.data.Movie
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun Details(movie: Movie, modifier: Modifier = Modifier) {
Column(
modifier = Modifier
.padding(vertical = 32.dp, horizontal = 48.dp)
) {
Text(text = movie.title)
Text(text = movie.studio)
Text(text = movie.title)
}
}
L'objet Modifier
spécifié dans le paramètre de la fonction Composable
Details
est utilisé dans la tâche suivante.
Afficher l'image de fond associée à un objet Movie
donné
Un objet Movie
possède un attribut backgroundImageUrl
qui spécifie l'emplacement de l'image de fond du film décrit par l'objet.
Pour afficher l'image de fond d'un film donné, procédez comme suit :
- Ajoutez une fonction
Composable
Box
en tant que wrapper de la fonctionComposable
Column
avec l'objetmodifier
transmis via la fonctionComposable
Details
. - Appelez la méthode
fillMaxSize
de l'objetmodifier
dans la fonctionComposable
Box
afin que cette dernière remplisse la taille maximale pouvant être allouée à la fonctionComposable
Details
. - Ajoutez une fonction
Composable
AsyncImage
avec les paramètres suivants à la fonctionComposable
Box
:
- Définissez la valeur de l'attribut
backgroundImageUrl
de l'objetMovie
donné sur un paramètremodel
. - Transmettez la valeur
null
à un paramètrecontentDescription
.
- Transmettez un objet
ContentScale.Crop
à un paramètrecontentScale
. Pour afficher les différentes optionsContentScale
, consultez la section Échelle de contenu. - Transmettez la valeur renvoyée par la méthode
Modifier.fillMaxSize
au paramètremodifier
. - Définissez une marge verticale de 32 dp et une marge horizontale de 48 dp autour de la colonne en définissant un objet
Modifier
créé en appelant la méthodeModifier.padding
.
Details.kt
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
import coil.compose.AsyncImage
import com.example.tvcomposeintroduction.data.Movie
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun Details(movie: Movie, modifier: Modifier = Modifier) {
Box(modifier = modifier.fillMaxSize()) {
AsyncImage(
model = movie.cardImageUrl,
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
Column(
modifier = Modifier
.padding(vertical = 32.dp, horizontal = 48.dp)
) {
Text(
text = movie.title,
)
Text(
text = movie.studio,
)
Text(
text = movie.title,
)
}
}
}
Utiliser l'objet MaterialTheme
pour une thématisation cohérente
L'objet MaterialTheme
contient des fonctions qui font référence à des valeurs de thème actuelles, comme celles des classes Typography
et [ColorScheme
][ColorScheme].
Pour faire référence à l'objet MaterialTheme
dans le cadre d'une thématisation cohérente, procédez comme suit :
- Définissez la propriété
MaterialTheme.typography.headlineLarge
sur le style de texte du titre du film. - Définissez la propriété
MaterialTheme.typography.headlineMedium
sur le style de texte des deux autres fonctionsComposable
Text
. - Définissez la propriété
MaterialTheme.colorScheme.background
sur la couleur d'arrière-plan de la fonctionComposable
Column
avec la méthodeModifier.background
.
[ColorScheme] : /reference/kotlin/androidx/tv/material3/ColorScheme)
Details.kt
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text
import coil.compose.AsyncImage
import com.example.tvcomposeintroduction.data.Movie
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun Details(movie: Movie, modifier: Modifier = Modifier) {
Box(modifier = modifier.fillMaxSize()) {
AsyncImage(
model = movie.cardImageUrl,
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
Column(
modifier = Modifier
.padding(vertical = 32.dp, horizontal = 48.dp)
) {
Text(
text = movie.title,
style = MaterialTheme.typography.headlineLarge,
)
Text(
text = movie.studio,
style = MaterialTheme.typography.headlineMedium,
)
Text(
text = movie.title,
style = MaterialTheme.typography.headlineMedium,
)
}
}
}
5. Permettre la navigation entre les écrans
Vous disposez à présent du navigateur de catalogue et de l'écran d'informations. Lorsqu'un utilisateur sélectionne un contenu à partir du navigateur de catalogue, celui-ci doit passer à l'écran d'informations. Pour ce faire, utilisez le modificateur clickable
pour ajouter un écouteur event
à la fonction Composable
MovieCard
. Lorsque vous appuyez sur le bouton central de la croix directionnelle, la méthode CatalogBrowserViewModel#showDetails
est appelée avec l'objet Movie associé à la fonction Composable
MovieCard
en tant qu'argument.
- Ouvrez le fichier
com.example.tvcomposeintroduction.ui.screens.CatalogBrowser
. - Transmettez une fonction lambda à la fonction
Composable
MovieCard
avec un paramètreonClick
. - Appelez le rappel
onMovieSelected
avec l'objet Movie associé à la fonctionComposable
MovieCard
.
CatalogBrowser.kt
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.tv.foundation.lazy.list.TvLazyColumn
import androidx.tv.foundation.lazy.list.TvLazyRow
import androidx.tv.foundation.lazy.list.items
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
import com.example.tvcomposeintroduction.data.Movie
import com.example.tvcomposeintroduction.ui.components.MovieCard
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = viewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsState()
TvLazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
items(categoryList) { category ->
Text(text = category.name)
TvLazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(category.movieList) { movie ->
MovieCard(movie = movie, onClick = { onMovieSelected(movie) })
}
}
}
}
}
6. Ajouter un carrousel au navigateur de catalogue pour mettre en avant une sélection de contenus
Le carrousel est un élément d'UI couramment adapté. Il met automatiquement à jour les diapositives après une durée spécifiée. Cette fonctionnalité est généralement utilisée pour mettre en avant des sélections de contenus.
Pour ajouter un carrousel au navigateur de catalogue afin de mettre en avant une sélection de films dans la liste de contenus, procédez comme suit :
- Ouvrez le fichier
com.example.tvcomposeintroduction.ui.screens.CatalogBrowser
. - Appelez la fonction
item
pour ajouter un élément à la fonctionComposable
TvLazyColumn
. - Déclarez
featuredMovieList
en tant que propriété déléguée dans le lambda transmis à la fonctionitem
. Définissez ensuite l'objetState
comme délégué ; il est collecté à partir de l'attributcatalogBrowserViewModel.featuredMovieList
. - Appelez la fonction
Composable
Carousel
dans la fonctionitem
, puis transmettez les paramètres suivants :
- La taille de la variable
featuredMovieList
via un paramètreslideCount
- Un objet
Modifier
permettant de spécifier la taille du carrousel à l'aide des méthodesModifier.fillMaxWidth
etModifier.height
. La fonctionComposable
Carousel
utilise une hauteur de 376 dp lorsqu'elle transmet une valeur376.dp
à la méthodeModifier.height
- Un Lambda appelé avec une valeur entière qui spécifie l'index de l'élément visible du carrousel
- Récupérez l'objet
Movie
à partir de la variablefeaturedMovieList
et de la valeur d'index donnée. - Ajoutez une fonction
Composable
CarouselSlide
à la fonctionComposable
Carousel
. - Ajoutez une fonction
Composable
Text
à la fonctionCarouselSlide
Composable
pour afficher le titre du film.
CatalogBrowser.kt
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.tv.foundation.lazy.list.TvLazyColumn
import androidx.tv.foundation.lazy.list.TvLazyRow
import androidx.tv.foundation.lazy.list.items
import androidx.tv.material3.Carousel
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
import com.example.tvcomposeintroduction.data.Movie
import com.example.tvcomposeintroduction.ui.components.MovieCard
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = viewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsState()
TvLazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
item {
val featuredMovieList by catalogBrowserViewModel.featuredMovieList.collectAsState()
Carousel(
slideCount = featuredMovieList.size,
modifier = Modifier
.fillMaxWidth()
.height(376.dp)
) { indexOfCarouselSlide ->
val featuredMovie =
featuredMovieList[indexOfCarouselSlide]
CarouselSlide {
Text(text = featuredMovie.title)
}
}
}
items(categoryList) { category ->
Text(text = category.name)
TvLazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(category.movieList) { movie ->
MovieCard(movie = movie, onClick = { onMovieSelected(movie) })
}
}
}
}
}
Afficher des images de fond
La fonction Composable
CarouselSlide
peut utiliser un autre lambda pour spécifier l'affichage de son arrière-plan.
Pour afficher des images de fond, procédez comme suit :
- Transmettez un lambda à la fonction
Composable
CarouselSlide
avec le paramètrebackground
. - Appelez la fonction
Composable
AsyncImage
pour charger l'image de fond associée à l'objetMovie
en arrière-plan de la fonctionComposable
CarouselSlide
. - Modifiez la position et le style du texte de la fonction
Composable
Text
dans la fonctionComposable
CarouselSlide
pour une meilleure visibilité. - Définissez un espace réservé dans la fonction
Composable
AsyncImage
pour éviter un décalage de mise en page. Le code de démarrage contient un espace réservé en tant que drawable auquel vous pouvez faire référence avecR.drawable.placeholder
.
CatalogBrowser.kt
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.tv.foundation.lazy.list.TvLazyColumn
import androidx.tv.foundation.lazy.list.TvLazyRow
import androidx.tv.foundation.lazy.list.items
import androidx.tv.material3.Carousel
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
import coil.compose.AsyncImage
import com.example.tvcomposeintroduction.R
import com.example.tvcomposeintroduction.data.Movie
import com.example.tvcomposeintroduction.ui.components.MovieCard
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = viewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsState()
TvLazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
item {
val featuredMovieList by catalogBrowserViewModel.featuredMovieList.collectAsState()
Carousel(
slideCount = featuredMovieList.size,
modifier = Modifier
.fillMaxWidth()
.height(376.dp),
) { indexOfCarouselItem ->
val featuredMovie = featuredMovieList[indexOfCarouselItem]
CarouselSlide(
background = {
AsyncImage(
model = featuredMovie.backgroundImageUrl,
contentDescription = null,
placeholder = painterResource(
id = R.drawable.placeholder
),
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize(),
)
},
) {
Text(text = featuredMovie.title)
}
}
}
items(categoryList) { category ->
Text(text = category.name)
TvLazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(category.movieList) { movie ->
MovieCard(movie = movie, onClick = { onMovieSelected(movie) })
}
}
}
}
}
Ajouter une transition vers l'écran d'informations
Vous pouvez permettre aux utilisateurs de cliquer sur la fonction Composable
CarouselSlide
.
Pour permettre aux utilisateurs d'afficher les informations du film dans le carrousel visible sur l'écran d'informations, procédez comme suit :
- Transmettez la valeur renvoyée par la méthode
Modifier.clickable
à la fonctionComposable
CarouselSlide
via le paramètremodifier
. - Appelez la fonction
onMovieSelected
avec l'objetMovie
pour la fonctionComposable
CarouselSlide
visible dans le lambda transmis à la méthodeModifier.clickable
.
CatalogBrowser.kt
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.tv.foundation.lazy.list.TvLazyColumn
import androidx.tv.foundation.lazy.list.TvLazyRow
import androidx.tv.foundation.lazy.list.items
import androidx.tv.material3.Carousel
import androidx.tv.material3.ExperimentalTvMaterial3Api
import androidx.tv.material3.Text
import coil.compose.AsyncImage
import com.example.tvcomposeintroduction.R
import com.example.tvcomposeintroduction.data.Movie
import com.example.tvcomposeintroduction.ui.components.MovieCard
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = viewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsState()
TvLazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
item {
val featuredMovieList by catalogBrowserViewModel.featuredMovieList.collectAsState()
Carousel(
slideCount = featuredMovieList.size,
modifier = Modifier
.fillMaxWidth()
.height(376.dp),
) { indexOfCarouselItem ->
val featuredMovie = featuredMovieList[indexOfCarouselItem]
CarouselSlide(
background = {
AsyncImage(
model = featuredMovie.backgroundImageUrl,
contentDescription = null,
placeholder = painterResource(
id = R.drawable.placeholder
),
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize(),
)
},
modifier = Modifier.clickable { onMovieSelected(featuredMovie) }
) {
Text(text = featuredMovie.title)
}
}
}
items(categoryList) { category ->
Text(text = category.name)
TvLazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(category.movieList) { movie ->
MovieCard(movie = movie, onClick = { onMovieSelected(movie) })
}
}
}
}
}
7. Télécharger le code de solution
Pour télécharger le code de solution de cet atelier de programmation, effectuez l'une des opérations suivantes :
- Cliquez sur le bouton suivant pour le télécharger au format .zip, puis décompressez-le et ouvrez-le dans Android Studio.
- Récupérez-le avec Git :
$ git clone https://github.com/android/tv-codelabs.git $ cd tv-codelabs $ git checkout solution $ cd IntroductionToComposeForTV
8. Félicitations.
Félicitations ! Vous avez appris les principes de base de Compose pour la télévision :
- Comment implémenter un écran pour afficher une liste de contenu en combinant TvLazyColumn et TvLazyLow
- Comment implémenter un écran de base pour afficher les détails du contenu
- Comment ajouter des transitions lors du passage d'un écran à une autre