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.
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
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 Composable
. A função Composable
CatalogBrowser
está no arquivo CatalogBrowser.kt
. Implemente a tela do navegador de catálogo nesta função Composable
.
O código inicial tem um ViewModel chamado classe CatalogBrowserViewModel
que tem vários atributos e métodos para recuperar objetos Movie
que descrevem o conteúdo do filme. Você implementa um navegador de catálogo com objetos Movie
recuperados.
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 = {}
) {
}
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 collectAsState
dele. Um objeto Category
tem o atributo name
, 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.kt
do código inicial e adicione uma funçãoComposable
TvLazyColumn
à funçãoComposable
CatalogBrowser
. - Chame o método
catalogBrowserViewModel.categoryList.collectAsState()
para coletar o fluxo como um objetoState
. - Declare
categoryList
como uma propriedade delegada do objetoState
que você criou na etapa anterior. - Chame a função
items
com a variávelcategoryList
como parâmetro. - Chame a função
Composable
Text
com o nome da categoria como o parâmetro transmitido como um argumento do 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)
}
}
}
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
Composable
TvLazyRow
e transmita um lambda a ela. - No lambda, chame a função
items
com acategory
.movieList
e, em seguida, transmita um lambda a ela. - No lambda transmitido à função
items
, chame a funçãoComposable
MovieCard
com um objetoMovie
.
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)
}
}
}
}
}
Opcional: ajustar o layout
- Para definir a lacuna entre as categorias, transmita um objeto
Arrangement
à funçãoComposable
TvLazyColumn
com 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çãoComposable
TvLazyRow
com o parâmetrohorizontalArrangement
. - Para definir um recuo na coluna, transmita um objeto
PaddingValue
com o parâmetrocontentPadding
.
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. Implementar a tela de detalhes
A tela de detalhes mostra os detalhes do filme selecionado. Há uma função Composable
Details
no arquivo Details.kt
. Adicione o código a essa função para implementar a tela de detalhes.
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) {
}
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
Composable
Column
e defina a liberação horizontal em 32 dp e a horizontal em 48 dp ao redor da coluna com o objetoModifier
criado pelo métodoModifier.padding
. - Adicione uma função
Composable
Text
para mostrar o título do filme. - Adicione uma função
Composable
Text
para mostrar o nome do estúdio. - Adicione uma função
Composable
Text
para mostrar a descrição do filme.
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)
}
}
O objeto Modifier
especificado no parâmetro da função Composable
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
Composable
Box
como um wrapper da funçãoComposable
Column
com o objetomodifier
transmitido pela funçãoComposable
Details
. - Na função
Composable
Box
, chame o métodofillMaxSize
do objetomodifier
para que a funçãoComposable
Box
preencha o tamanho máximo que pode ser alocado para a funçãoComposable
Details
. - Adicione uma função
Composable
AsyncImage
à funçãoComposable
Box
com os seguintes parâmetros:
- Define o valor do atributo
backgroundImageUrl
do objetoMovie
especificado como um parâmetromodel
. - Transmita
null
a um parâmetrocontentDescription
.
- Transmita um objeto
ContentScale.Crop
a um parâmetrocontentScale
. Para conferir as diferentes opções deContentScale
, consulte Escala de conteúdo. - Transmita o valor de retorno do método
Modifier.fillMaxSize
ao parâmetromodifier
. - Configure um objeto
Modifier
criado chamando o métodoModifier.padding
para definir a liberação da coluna horizontal em 32 dp e a vertical em 48 dp.
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,
)
}
}
}
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
][ColorScheme].
Para consultar o objeto MaterialTheme
e ter uma aplicação consistente de temas, siga estas etapas:
- Defina a propriedade
MaterialTheme.typography.headlineLarge
como o estilo de texto do título do filme. - Defina a propriedade
MaterialTheme.typography.headlineMedium
como o estilo de texto das outras duas funçõesComposable
Text
. - Defina a propriedade
MaterialTheme.colorScheme.background
como a cor de fundo da funçãoComposable
Column
com o métodoModifier.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. 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 método clickable
para adicionar um listener event
à função Composable
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 Composable
MovieCard
como um argumento.
- Abra o arquivo
com.example.tvcomposeintroduction.ui.screens.CatalogBrowser
. - Transmita uma função lambda à função
Composable
MovieCard
com um parâmetroonClick
. - Chame o callback
onMovieSelected
com o objeto filme associado à funçãoComposable
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. 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
item
para adicionar um item à funçãoTvLazyColumn
Composable
. - Declare
featuredMovieList
como uma propriedade delegada no lambda transmitido à funçãoitem
e defina o objetoState
a ser delegado, que é coletado do atributocatalogBrowserViewModel.featuredMovieList
. - Chame a função
Composable
Carousel
dentro da funçãoitem
e transmita os seguintes parâmetros:
- O tamanho da variável
featuredMovieList
por meio de um parâmetroslideCount
. - Um objeto
Modifier
para especificar o tamanho do carrossel com os métodosModifier.fillMaxWidth
eModifier.height
. A funçãoComposable
Carousel
usa 376 dp de altura, transmitindo um valor376.dp
ao métodoModifier.height
. - Um lambda chamado com um valor inteiro que indica o índice do item do carrossel visível.
- Recupere o objeto
Movie
da variávelfeaturedMovieList
e do valor de índice fornecido. - Adicione uma função
Composable
CarouselSlide
à funçãoComposable
Carousel
. - Adicione uma função
Composable
Text
à funçãoComposable
CarouselSlide
para mostrar o título do filme.
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) })
}
}
}
}
}
Mostrar imagens de plano de fundo
A função Composable
CarouselSlide
pode usar outro lambda para especificar como mostrar o plano de fundo da função Composable
CarouselSlide
.
Para mostrar imagens de plano de fundo, siga estas etapas:
- Transmita um lambda à função
Composable
CarouselSlide
com o parâmetrobackground
. - Chame a função
Composable
AsyncImage
para carregar a imagem de plano de fundo associada ao objetoMovie
no segundo plano da funçãoComposable
CarouselSlide
. - Atualize a posição e o estilo do texto da função
Composable
Text
na funçãoComposable
CarouselSlide
para melhorar a visibilidade. - Defina um marcador de posição para a função
Composable
AsyncImage
com 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
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) })
}
}
}
}
}
Adicionar uma transição de telas à tela de detalhes
Você pode permitir que os usuários cliquem na função Composable
CarouselSlide
.
Para que os usuários possam conferir os detalhes do filme no item de carrossel visível na tela de detalhes, siga estas etapas:
- Transmita o valor de retorno do método
Modifier.clickable
para a funçãoCarouselSlide
Composable
usando o parâmetromodifier
. - Chame a função
onMovieSelected
com o objetoMovie
para a funçãoComposable
CarouselSlide
visível no lambda transmitido ao métodoModifier.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. 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
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 TvLazyColumn e TvLazyLow.
- A implementação básica de tela para mostrar detalhes do conteúdo.
- Como adicionar transições entre as duas telas.