1. Antes de começar
Compose para TV é o framework de interface mais recente para desenvolver apps executados no Android TV. Ele oferece todos os benefícios do Jetpack Compose para apps de TV, o que facilita a criação de interfaces incríveis e funcionais para seu app. Confira alguns benefícios específicos do Compose para TV:
- Flexibilidade. O Compose pode ser usado para criar qualquer tipo de interface, desde layouts simples a animações complexas. Os componentes funcionam imediatamente, mas também podem ser personalizados e estilizados para atender às necessidades do seu app.
- Desenvolvimento simplificado e acelerado. O Compose é compatível com códigos já existentes e permite que os desenvolvedores criem apps com menos código.
- Intuição: o Compose usa uma sintaxe declarativa que torna intuitivas a mudança da interface e a depuração, compreensão e revisão do código.
Um caso de uso comum para apps de TV é o consumo de mídia. Os usuários navegam por catálogos de conteúdo e selecionam aquele que querem assistir. O conteúdo pode ser um filme, um programa de TV ou um podcast. Depois de selecionar um conteúdo, os usuários podem conferir mais informações sobre ele, por exemplo, uma descrição curta, a duração da reprodução e o nome dos criadores. Neste codelab, você vai aprender a implementar uma tela para um navegador de catálogo e uma tela de detalhes com o Compose para TV.
Pré-requisitos
- Experiência com a sintaxe do Kotlin, incluindo lambdas.
- Experiência básica com o Compose. Se você não conhece o Compose, conclua o codelab Noções básicas do Jetpack Compose.
- Conhecimento básico de combináveis e modificadores.
- Qualquer um destes dispositivos para executar o app de exemplo:
- Um dispositivo Android TV
- Um dispositivo virtual Android com um perfil na categoria de definição de dispositivo de TV
O que você vai criar
- Um app de player de vídeo com uma tela de navegador de catálogo e uma tela de detalhes.
- Uma tela de navegador de catálogo que mostra uma lista de vídeos para os usuários escolherem. Ela tem a seguinte aparência:

- Uma tela de detalhes que mostra os metadados de um vídeo selecionado, por exemplo, título, descrição e duração. Ela tem a seguinte aparência:

O que é necessário
- A versão mais recente do Android Studio
- Um dispositivo Android TV ou virtual na categoria de dispositivo de TV
2. Começar a configuração
Para receber o código que contém a configuração básica e de aplicação de temas para este codelab, siga um destes procedimentos:
- Clone o código deste repositório do GitHub:
$ git clone https://github.com/android/tv-codelabs.git
A ramificação main contém o código inicial, e a ramificação solution contém o código da solução.
- Faça o download do arquivo
main.zip, que contém o código inicial, e do arquivosolution.zip, que contém o código da solução.
Depois de fazer o download do código, abra a pasta do projeto IntroductionToComposeForTV no Android Studio. Está tudo pronto para começar.
3. Implementar a tela do navegador de catálogo
A tela do navegador de catálogo permite que os usuários procurem catálogos de filmes. Implemente a tela do navegador de catálogo como uma função combinável. A função combinável CatalogBrowser está no arquivo CatalogBrowser.kt. Implemente a tela do navegador de catálogo nesta função combinável.
O código inicial tem um ViewModel conhecido como a classe CatalogBrowserViewModel que tem vários atributos e métodos para extrair objetos Movie que descrevem o conteúdo do filme. Você implementa um navegador de catálogo com objetos Movie recuperados.
CatalogBrowser.kt
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
}
Mostrar os nomes das categorias
É possível acessar uma lista de categorias com o atributo catalogBrowserViewModel.categoryList, que é um fluxo de uma lista de categorias (Category). O fluxo é coletado como um objeto Compose State chamando o método collectAsStateWithLifecycle dele. Um objeto Category tem o atributo name, que é um valor String que representa o nome da categoria.
Para mostrar os nomes das categorias, siga estas etapas:
- No Android Studio, abra o arquivo
CatalogBrowser.ktdo código inicial e adicione uma função combinávelLazyColumnà função combinávelCatalogBrowser. - Chame o método
catalogBrowserViewModel.categoryList.collectAsStateWithLifeCycle()para coletar o fluxo como um objetoState. - Declare
categoryListcomo uma propriedade delegada do objetoStateque você criou na etapa anterior. - Chame a função
itemscom a variávelcategoryListcomo parâmetro. - Chame a função combinável
Textcom o nome da categoria como o parâmetro transmitido como um argumento da 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)
}
}
}
Mostrar a lista de conteúdo de cada categoria
Um objeto Category tem outro atributo chamado movieList. O atributo é uma lista de objetos Movie que representam os filmes que pertencem à categoria.
Para mostrar a lista de conteúdos de cada categoria, siga estas etapas:
- Adicione a função combinável
LazyRowe transmita uma lambda a ela. - Na lambda, chame a função
itemscom o valor de atributocategory.movieListe, em seguida, transmita uma lambda a ela. - Na lambda transmitida à função
items, chame a função combinávelMovieCardcom um objetoMovie.
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)
}
}
}
}
}
Opcional: ajustar o layout
- Para definir a lacuna entre as categorias, transmita um objeto
Arrangementà função combinávelLazyColumncom o parâmetroverticalArrangement. O objetoArrangementé criado chamando o métodoArrangement#spacedBy. - Para definir a lacuna entre os cartões de filmes, transmita um objeto
Arrangementà função combinávelLazyRowcom o parâmetrohorizontalArrangement. - Para definir um recuo na coluna, transmita um objeto
PaddingValuecom o parâmetrocontentPadding.
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. Implementar a tela de detalhes
A tela de detalhes mostra os detalhes do filme selecionado. Há uma função combinável Details no arquivo Details.kt. Adicione o código a essa função para implementar a tela de detalhes.
Details.kt
@Composable
fun Details(movie: Movie, modifier: Modifier = Modifier) {
}
Mostrar o título, o nome do estúdio e a descrição do filme
Um objeto Movie tem estes três atributos de string como metadados do filme:
title: o título do filme.studio: o nome do estúdio que produziu o filme.description: um breve resumo do filme.
Para mostrar esses metadados na tela de detalhes, siga estas etapas:
- Adicione uma função combinável
Columne defina a área livre vertical como 32 dp e a horizontal como 48 dp ao redor da coluna com o objetoModifiercriado pelo métodoModifier.padding. - Adicione uma função combinável
Textpara mostrar o título do filme. - Adicione uma função combinável
Textpara mostrar o nome do estúdio. - Adicione uma função combinável
Textpara mostrar a descrição do filme.
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)
}
}
O objeto Modifier especificado no parâmetro da função combinável Details é usado na próxima tarefa.
Mostrar a imagem de plano de fundo associada a um determinado objeto Movie
Um objeto Movie tem um atributo backgroundImageUrl que indica o local da imagem de plano de fundo do filme descrito pelo objeto.
Para mostrar a imagem de plano de fundo de um determinado filme, siga estas etapas:
- Adicione uma função combinável
Boxcomo um wrapper da função combinávelColumncom o objetomodifiertransmitido pela função combinávelDetails. - Na função combinável
Box, chame o métodofillMaxSizedo objetomodifierpara que a função combinávelBoxpreencha o tamanho máximo que pode ser alocado para a função combinávelDetails. - Adicione uma função combinável
AsyncImageà funçãoBoxcom os parâmetros abaixo:
- Define o valor do atributo
backgroundImageUrldo objetoMovieespecificado como um parâmetromodel. - Transmita
nulla um parâmetrocontentDescription.
- Transmita um objeto
ContentScale.Cropa um parâmetrocontentScale. Para conferir as diferentes opções deContentScale, consulte Escala de conteúdo. - Transmita o valor de retorno do método
Modifier.fillMaxSizeao parâmetromodifier.
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)
}
}
}
Consultar o objeto MaterialTheme para obter uma aplicação consistente de temas
O objeto MaterialTheme contém funções para indicar valores de tema atuais, por exemplo, os das classes Typography e ColorScheme.
Para consultar o objeto MaterialTheme e ter uma aplicação consistente de temas, siga estas etapas:
- Defina a propriedade
MaterialTheme.typography.displayMediumcomo o estilo de texto do título do filme. - Defina a propriedade
MaterialTheme.typography.bodySmallcomo o estilo de texto da segunda função combinávelText. - Defina a propriedade
MaterialTheme.colorScheme.backgroundcomo a cor de fundo da funçãoColumncom o métodoModifier.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)
}
}
}
Opcional: ajustar o layout
Para ajustar o layout da função combinável Details, siga estas etapas:
- Defina a função combinável
Boxpara usar todo o espaço disponível com o modificadorfillMaxSize. - Defina o segundo plano da função combinável
Boxcom o modificadorbackgroundpara preencher o segundo plano com um gradiente linear criado ao chamar a funçãoBrush.linearGradientcom uma lista de objetosColorcontendo o valorMaterialTheme.colorScheme.backgroundeColor.Transparent - Defina a área livre horizontal
48.dpe vertical24.dpao redor da função combinávelColumncom o modificadorpadding - Defina a largura da função combinável
Columncom o modificadorwidth, que é criado chamando a funçãoModifier.widthcom o valor0.5f. - Adicione o espaçamento
8.dpentre a segunda função combinávelTexte o terceiro combinávelTextusandoSpacer. A altura da função combinávelSpaceré especificada com o modificadorheight, que é criado com a funçãoModifier.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. Adicionar navegação entre as telas
Agora você tem a tela do navegador de catálogo e as telas de detalhes. Depois que um usuário seleciona o conteúdo na tela do navegador de catálogo, é necessário mudar para a tela de detalhes. Para que isso seja possível, use o modificador clickable para adicionar um listener event à função combinável MovieCard. Quando o botão central do botão direcional é pressionado, o método CatalogBrowserViewModel#showDetails é chamado, apresentando o objeto do filme associado à função combinável MovieCard como um argumento.
- Abra o arquivo
com.example.tvcomposeintroduction.ui.screens.CatalogBrowser. - Transmita uma função lambda à função combinável
MovieCardcom um parâmetroonClick. - Chame o callback
onMovieSelectedcom o objeto do filme associado à função combinávelMovieCard.
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. Adicionar um carrossel à tela do navegador de catálogo para realçar o conteúdo em destaque
O carrossel é um componente da interface comumente adaptado que atualiza automaticamente os slides após uma duração específica. É usado normalmente para realçar o conteúdo em destaque.
Para adicionar um carrossel à tela do navegador de catálogo e realçar filmes na lista de conteúdo em destaque, siga estas etapas:
- Abra o arquivo
com.example.tvcomposeintroduction.ui.screens.CatalogBrowser. - Chame a função
itempara adicionar um item à função combinávelLazyColumn. - Declare
featuredMovieListcomo uma propriedade delegada na lambda transmitida à funçãoiteme defina o objetoStatea ser delegado, que é coletado do atributocatalogBrowserViewModel.featuredMovieList. - Chame a função combinável
Carouseldentro da funçãoiteme transmita estes parâmetros:
- O tamanho da variável
featuredMovieListpor um parâmetroslideCount. - Um objeto
Modifierpara especificar o tamanho do carrossel com os métodosModifier.fillMaxWidtheModifier.height. A função combinávelCarouselusa 376 dp de altura, transmitindo um valor376.dpao métodoModifier.height. - Uma lambda chamada com um valor inteiro que indica o índice do item do carrossel visível.
- Extraia o objeto
Movieda variávelfeaturedMovieListe do valor de índice fornecido. - Adicione uma função combinável
Boxà função combinávelCarousel. - Adicione uma função combinável
Textà função combinávelBoxpara mostrar o título do filme.
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) })
}
}
}
}
}
Mostrar imagens de plano de fundo
A função combinável Box coloca um componente em cima de outro. Consulte Conceitos básicos de layout para mais detalhes.
Para mostrar imagens de plano de fundo, siga estas etapas:
- Chame a função combinável
AsyncImagepara carregar a imagem de plano de fundo associada ao objetoMovieantes da função combinávelText. - Atualize a posição e o estilo do texto da função combinável
Textpara melhorar a visibilidade. - Defina um marcador de posição para a função combinável
AsyncImagecom o objetivo de evitar a mudança de layout. O código inicial tem um marcador de posição como um drawable que pode ser referenciado com oR.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) })
}
}
}
}
}
Adicionar uma transição de telas à tela de detalhes
É possível adicionar um Button ao carrossel para que os usuários possam acionar uma transição para a tela de detalhes clicando no botão.
Para que os usuários possam conferir os detalhes do filme no carrossel visível na tela de detalhes, siga estas etapas:
- Chame a função combinável
Columnno elemento combinávelBoxno combinávelCarousel - Mova o elemento combinável
TextnoCarouselpara a função combinávelColumn. - Chame a função combinável
Buttondepois da funçãoTextna funçãoColumn. - Chame a função combinável
Textna funçãoButtoncom o valor de retorno da funçãostringResource, chamada comR.string.show_details. - Chame a função
onMovieSelectedcom a variávelfeaturedMoviena lambda transmitida ao parâmetroonClickda função combinávelButton.
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) })
}
}
}
}
}
Opcional: ajustar o layout
Para ajustar o layout do carrossel, siga estas etapas:
- Atribua o valor
backgroundColorcom o valorMaterialTheme.colorScheme.backgroundna função combinávelCarousel. - Unir a função combinável
Columna um elemento combinávelBox - Transmita o valor
Alignment.BottomStartao parâmetrocontentAlignmentdo componenteBox. - Transmita o modificador
fillMaxSizeao parâmetro modificador da função combinávelBox. O modificadorfillMaxSizeé criado com a funçãoModifier.fillMaxSize(). - Chame o método
drawBehind()no modificadorfillMaxSizetransmitido ao elemento combinávelBox. - Na lambda transmitida ao modificador
drawBehind, atribua o valorbrushcom um objetoBrushque é criado ao chamar a funçãoBrush.linearGradientcom uma lista de dois objetosColor. A lista é criada chamando a funçãolistOfcom os valoresbackgroundColoreColor.Transparent. - Chame
drawRectcom o objetobrushna lambda transmitida ao modificadordrawBehindpara criar uma camada srim sobre a imagem de plano de fundo - Especifique o padding da função combinável
Columncom o modificadorpadding, que é criado chamandoModifier.paddingcom o valor20.dp. - Adicione uma função combinável
Spacercom o valor20.dpentre os elementos combináveisTexteButtonna função combinávelColumn.
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. Acessar o código da solução
Para fazer o download do código da solução para este codelab, realize uma destas ações:
- Clique no botão a seguir para fazer o download como um arquivo ZIP. Em seguida, descompacte e abra esse arquivo no Android Studio.
- Recupere-o com o Git:
$ git clone https://github.com/android/tv-codelabs.git $ cd tv-codelabs $ git checkout solution $ cd IntroductionToComposeForTV
- Confira no GitHub (link em inglês).
8. Parabéns!
Parabéns! Você aprendeu as noções básicas do Compose para TV:
- Como implementar uma tela para mostrar uma lista de conteúdo combinando LazyColumn e LazyLow.
- A implementação básica de tela para mostrar detalhes do conteúdo.
- Como adicionar transições entre as duas telas.