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.
- N'importe lequel des appareils suivants devra exécuter l'application exemple :
- Un appareil Android TV
- Un appareil virtuel Android avec un profil dans la catégorie de définition des appareils TV
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
- Un appareil Android TV ou un appareil virtuel dans la catégorie "Téléviseur"
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
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
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 collectAsStateWithLifecycle. Un objet Category possède l'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.ktdu code de démarrage, puis ajoutez une fonction composableLazyColumnà la fonction composableCatalogBrowser. - Appelez la méthode
catalogBrowserViewModel.categoryList.collectAsStateWithLifeCycle()pour collecter le flux en tant qu'objetState. - Déclarez
categoryListen tant que propriété déléguée de l'objetStatecréé à l'étape précédente. - Appelez la fonction
itemsavec la variablecategoryListen tant que paramètre. - Appelez la fonction composable
Textavec le nom de la catégorie comme paramètre transmis en tant qu'argument du lambda.
CatalogBrowser.kt
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by catalogBrowserViewModel.categoryList.collectAsStateWithLifecycle()
LazyColumn(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
LazyRow, puis transmettez-lui un lambda. - Dans le lambda, appelez la fonction
itemsaveccategoryet la valeur d'attributmovieList, puis transmettez-lui un lambda. - Dans le lambda transmis à la fonction
items, appelez la fonction composableMovieCardavec un objetMovie.
CatalogBrowser.kt
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsStateWithLifecycle()
LazyColumn(modifier = modifier) {
items(categoryList) { category ->
Text(text = category.name)
LazyRow {
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 fonction composableLazyColumnavec le paramètreverticalArrangement. L'objetArrangementest créé en appelant la méthodeArrangement#spacedBy. - Pour définir l'écart entre les fiches de films, transmettez un objet
Arrangementà la fonction composableLazyRowavec le paramètrehorizontalArrangement. - Pour définir un retrait au niveau de la colonne, transmettez un objet
PaddingValueavec le paramètrecontentPadding.
CatalogBrowser.kt
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsStateWithLifeCycle()
LazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
items(categoryList) { category ->
Text(text = category.name)
LazyRow(
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
@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'objetModifiercréé par la méthodeModifier.padding. - Ajoutez une fonction composable
Textpour afficher le titre du film. - Ajoutez une fonction composable
Textpour afficher le nom du studio. - Ajoutez une fonction composable
Textpour afficher la description du film.
Details.kt
@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.description)
}
}
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
Boxen tant que wrapper de la fonction composableColumnavec l'objetmodifiertransmis via la fonction composableDetails. - Dans la fonction composable
Box, appelez la méthodefillMaxSizede l'objetmodifierpour que la fonction composableBoxremplisse la taille maximale pouvant être allouée à la fonction composableDetails. - Ajoutez une fonction composable
AsyncImageavec les paramètres suivants à la fonction composableBox:
- Définissez la valeur de l'attribut
backgroundImageUrlde l'objetMoviedonné 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.fillMaxSizeau paramètremodifier.
Details.kt
@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 {
Text(
text = movie.title,
)
Text(
text = movie.studio,
)
Text(text = movie.description)
}
}
}
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.
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.displayMediumsur le style de texte du titre du film. - Définissez la propriété
MaterialTheme.typography.bodySmallsur le style de texte des deuxièmes fonctions composablesText. - Définissez la propriété
MaterialTheme.colorScheme.backgroundsur la couleur d'arrière-plan de la fonction composableColumnavec la méthodeModifier.background.
Details.kt
@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
.background(MaterialTheme.colorScheme.background),
) {
Text(
text = movie.title,
style = MaterialTheme.typography.displayMedium,
)
Text(
text = movie.studio,
style = MaterialTheme.typography.bodySmall,
)
Text(text = movie.description)
}
}
}
Facultatif : ajuster la mise en page
Pour ajuster la mise en page de la fonction composable Details, procédez comme suit :
- Définissez la fonction composable
Boxpour utiliser la totalité de l'espace disponible avec le modificateurfillMaxSize. - Définissez l'arrière-plan de la fonction composable
Boxavec le modificateurbackgroundpour remplir l'arrière-plan avec un dégradé linéaire créé en appelant la fonctionBrush.linearGradientavec une liste d'objetsColorcontenant les valeursMaterialTheme.colorScheme.backgroundetColor.Transparent. - Définissez la marge horizontale
48.dpet la marge verticale24.dpautour de la fonction composableColumnavec le modificateurpadding. - Définissez la largeur de la fonction composable
Columnavec le modificateurwidthcréé en appelant la fonctionModifier.widthavec la valeur0.5f. - Ajoutez l'espace
8.dpentre la deuxième fonction composableTextet le troisième composableTextavecSpacer. La hauteur de la fonction composableSpacerest spécifiée avec le modificateurheightcréé avec la fonctionModifier.height.
Details.kt
@Composable
fun Details(movie: Movie, modifier: Modifier = Modifier) {
Box(modifier = modifier.fillMaxSize()) {
AsyncImage(
model = movie.cardImageUrl,
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
Box(
modifier = Modifier
.background(
Brush.linearGradient(
listOf(
MaterialTheme.colorScheme.background,
Color.Transparent
)
)
)
.fillMaxSize()
) {
Column(
modifier = Modifier
.padding(horizontal = 48.dp, vertical = 24.dp)
.fillMaxWidth(0.5f)
) {
Text(
text = movie.title,
style = MaterialTheme.typography.displayMedium,
)
Text(
text = movie.studio,
style = MaterialTheme.typography.bodySmall,
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = movie.description,
)
}
}
}
}
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, vous 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
MovieCardavec un paramètreonClick. - Appelez le rappel
onMovieSelectedavec l'objet Movie associé à la fonction composableMovieCard.
CatalogBrowser.kt
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsStateWithLifecycle()
LazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
items(categoryList) { category ->
Text(text = category.name)
LazyRow(
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
itempour ajouter un élément à la fonction composableLazyColumn. - Déclarez
featuredMovieListen tant que propriété déléguée dans le lambda transmis à la fonctionitem. Définissez ensuite l'objetStatecomme délégué ; il est collecté à partir de l'attributcatalogBrowserViewModel.featuredMovieList. - Appelez la fonction composable
Carouseldans la fonctionitem, puis transmettez les paramètres suivants :
- La taille de la variable
featuredMovieListvia un paramètreslideCount. - Un objet
Modifierpermettant de spécifier la taille du carrousel à l'aide des méthodesModifier.fillMaxWidthetModifier.height. La fonction composableCarouselutilise 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 variablefeaturedMovieListet de la valeur d'index donnée. - Ajoutez une fonction composable
Boxà la fonction composableCarousel. - Ajoutez une fonction composable
Textà la fonction composableBoxpour afficher le titre du film.
CatalogBrowser.kt
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsStateWithLifecycle()
LazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
item {
val featuredMovieList by catalogBrowserViewModel.featuredMovieList.collectAsStateWithLifecycle()
Carousel(
slideCount = featuredMovieList.size,
modifier = Modifier
.fillMaxWidth()
.height(376.dp)
) { indexOfCarouselSlide ->
val featuredMovie =
featuredMovieList[indexOfCarouselSlide]
Box {
Text(text = featuredMovie.title)
}
}
}
items(categoryList) { category ->
Text(text = category.name)
LazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(category.movieList) { movie ->
MovieCard(movie = movie, onClick = { onMovieSelected(movie) })
}
}
}
}
}
Afficher des images de fond
La fonction composable Box place un composant sur un autre. Pour en savoir plus, consultez Principes de base de la mise en page.
Pour afficher des images de fond, procédez comme suit :
- Appelez la fonction composable
AsyncImagepour charger l'image de fond associée à l'objetMovieavant la fonction composableText. - Mettez à jour la position et le style du texte de la fonction composable
Textpour une meilleure visibilité. - Définissez un espace réservé dans la fonction composable
AsyncImagepour é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
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsStateWithLifecycle()
LazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
item {
val featuredMovieList by catalogBrowserViewModel.featuredMovieList.collectAsStateWithLifecycle()
Carousel(
slideCount = featuredMovieList.size,
modifier = Modifier
.fillMaxWidth()
.height(376.dp),
) { indexOfCarouselItem ->
val featuredMovie = featuredMovieList[indexOfCarouselItem]
Box{
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)
LazyRow(
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 ajouter un Button au carrousel afin que les utilisateurs puissent déclencher une transition vers l'écran d'informations en cliquant sur le bouton.
Pour permettre aux utilisateurs d'afficher les informations du film dans le carrousel visible sur l'écran d'informations, procédez comme suit :
- Appelez la fonction composable
Columndans le composableBoxdu composableCarousel. - Déplacez le composable
TextdansCarouselvers la fonction composableColumn. - Appelez la fonction composable
Buttonaprès la fonction composableTextdans la fonction composableColumn. - Appelez la fonction composable
Textdans la fonction composableButtonavec la valeur renvoyée de la fonctionstringResourceappelée avecR.string.show_details. - Appelez la fonction
onMovieSelectedavec la variablefeaturedMoviedans le lambda transmis au paramètreonClickde la fonction composableButton.
CatalogBrowser.kt
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by
catalogBrowserViewModel.categoryList.collectAsStateWithLifecycle()
LazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(16.dp),
contentPadding = PaddingValues(horizontal = 48.dp, vertical = 32.dp)
) {
item {
val featuredMovieList by catalogBrowserViewModel.featuredMovieList.collectAsStateWithLifecycle()
Carousel(
slideCount = featuredMovieList.size,
modifier = Modifier
.fillMaxWidth()
.height(376.dp),
) { indexOfCarouselItem ->
val featuredMovie = featuredMovieList[indexOfCarouselItem]
Box {
AsyncImage(
model = featuredMovie.backgroundImageUrl,
contentDescription = null,
placeholder = painterResource(
id = R.drawable.placeholder
),
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize(),
)
Column {
Text(text = featuredMovie.title)
Button(onClick = { onMovieSelected(featuredMovie) }) {
Text(text = stringResource(id = R.string.show_details))
}
}
}
}
}
items(categoryList) { category ->
Text(text = category.name)
LazyRow(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(category.movieList) { movie ->
MovieCard(movie = movie, onClick = { onMovieSelected(movie) })
}
}
}
}
}
Facultatif : ajuster la mise en page
Pour ajuster la mise en page du carrousel, procédez comme suit :
- Attribuez la valeur
backgroundColoravec la valeurMaterialTheme.colorScheme.backgrounddans la fonction composableCarousel. - Encapsulez la fonction composable
Columnavec un composableBox. - Transmettez la valeur
Alignment.BottomStartau paramètrecontentAlignmentdu composantBox. - Transmettez le modificateur
fillMaxSizeau paramètre de modificateur de la fonction composableBox. Le modificateurfillMaxSizeest créé avec la fonctionModifier.fillMaxSize(). - Appelez la méthode
drawBehind()sur le modificateurfillMaxSizetransmis au composableBox. - Dans le lambda transmis au modificateur
drawBehind, attribuez la valeurbrushavec un objetBrushcréé en appelant la fonctionBrush.linearGradientavec une liste de deux objetsColor. Cette liste est créée en appelant la fonctionlistOfavec les valeursbackgroundColoretColor.Transparent. - Appelez
drawRectavec l'objetbrushdans le lambda transmis au modificateurdrawBehindpour créer une couche de contour sur l'image de fond. - Spécifiez la marge intérieure de la fonction composable
Columnavec le modificateurpaddingcréé en appelantModifier.paddingavec la valeur20.dp. - Ajoutez une fonction composable
Spaceravec une valeur20.dpentre le composableTextet le composableButtondans la fonction composableColumn.
CatalogBrowser.kt
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
val categoryList by catalogBrowserViewModel.categoryList.collectAsStateWithLifecycle()
LazyColumn(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(32.dp),
contentPadding = PaddingValues(horizontal = 58.dp, vertical = 36.dp)
) {
item {
val featuredMovieList by
catalogBrowserViewModel.featuredMovieList.collectAsStateWithLifecycle()
Carousel(
itemCount = featuredMovieList.size,
modifier = Modifier
.fillMaxWidth()
.height(376.dp),
) { indexOfCarouselItem ->
val featuredMovie = featuredMovieList[indexOfCarouselItem]
val backgroundColor = MaterialTheme.colorScheme.background
Box {
AsyncImage(
model = featuredMovie.backgroundImageUrl,
contentDescription = null,
placeholder = painterResource(
id = R.drawable.placeholder
),
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize(),
)
Box(
contentAlignment = Alignment.BottomStart,
modifier = Modifier
.fillMaxSize()
.drawBehind {
val brush = Brush.horizontalGradient(
listOf(backgroundColor, Color.Transparent)
)
drawRect(brush)
}
) {
Column(
modifier = Modifier.padding(20.dp)
) {
Text(
text = featuredMovie.title,
style = MaterialTheme.typography.displaySmall
)
Spacer(modifier = Modifier.height(28.dp))
Button(onClick = { onMovieSelected(featuredMovie) }) {
Text(text = stringResource(id = R.string.show_details))
}
}
}
}
}
}
items(categoryList) { category ->
Text(text = category.name)
LazyRow(
horizontalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier.height(200.dp)
) {
items(category.movieList) { movie ->
MovieCard(
movie,
onClick = {
onMovieSelected(it)
}
)
}
}
}
}
}
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 LazyColumn et LazyLow
- Comment implémenter un écran de base pour afficher les détails du contenu
- Comment ajouter des transitions lors du passage d'un écran à un autre