1. 开始之前
Compose for TV 是用于开发在 Android TV 上运行的应用程序的最新 UI 框架。它解锁了 Jetpack Compose for TV 应用程序的所有优势,这使得为您的应用程序构建美观且功能强大的 UI 变得更加容易。Compose for TV 的一些具体优势包括以下内容
- 灵活性。Compose 可用于创建任何类型的 UI,从简单的布局到复杂的动画。组件开箱即用,但也可以根据您的应用程序需求进行自定义和样式化。
- 简化和加速开发。Compose 与现有代码兼容,让开发者可以编写更少的代码来构建应用程序。
- 直观性:Compose 使用声明式语法,使更改 UI 以及调试、理解和审查代码变得直观。
TV 应用程序的常见用例是媒体消费。用户浏览内容目录并选择他们想要观看的内容。内容可以是电影、电视剧或播客。用户选择内容后,他们可能想要查看有关该内容的更多信息,例如简短说明、播放时长和创作者姓名。在本 Codelab 中,您将学习如何使用 Compose for TV 实现一个目录浏览器屏幕和一个详细信息屏幕。
先决条件
- 熟悉 Kotlin 语法,包括 lambda 表达式。
- 熟悉 Compose。如果您不熟悉 Compose,请完成Jetpack Compose 基础知识 Codelab。
- 了解可组合函数和修饰符。
- 以下任何设备均可运行示例应用程序
- Android TV 设备
- 使用 TV 设备定义类别中的配置文件的 Android 虚拟设备
您将构建的内容
- 一个具有目录浏览器屏幕和详细信息屏幕的视频播放器应用程序。
- 一个目录浏览器屏幕,显示用户可以选择的一系列视频。它看起来像下面的图像
- 一个详细信息屏幕,显示所选视频的元数据,例如标题、描述和时长。它看起来像下面的图像
您需要的内容
- Android Studio 的最新版本
- Android TV 设备或 TV 设备类别中的虚拟设备
2. 设置
要获取包含本 Codelab 的主题和基本设置的代码,请执行以下操作之一
- 从该 GitHub 存储库 克隆代码
$ git clone https://github.com/android/tv-codelabs.git
main
分支包含启动代码,solution
分支包含解决方案代码。
- 下载包含启动代码的
main.zip
文件,以及包含解决方案代码的solution.zip
文件。
现在您已经下载了代码,请在 Android Studio 中打开 IntroductionToComposeForTV 项目文件夹。现在您已经准备好开始。
3. 实现目录浏览器屏幕
目录浏览器屏幕允许用户浏览电影目录。您将目录浏览器实现为一个可组合函数。您可以在 CatalogBrowser.kt
文件中找到 CatalogBrowser
可组合函数。您将在该可组合函数中实现目录浏览器屏幕。
启动代码有一个名为 CatalogBrowserViewModel
类的 ViewModel,它具有多个属性和方法来检索描述电影内容的 Movie
对象。您将使用检索到的 Movie
对象实现目录浏览器。
CatalogBrowser.kt
@OptIn(ExperimentalTvMaterial3Api::class)
@Composable
fun CatalogBrowser(
modifier: Modifier = Modifier,
catalogBrowserViewModel: CatalogBrowserViewModel = hiltViewModel(),
onMovieSelected: (Movie) -> Unit = {}
) {
}
显示类别名称
您可以使用 catalogBrowserViewModel.categoryList
属性访问类别列表,该属性是 Category
列表的 流。流通过调用其 Compose State
对象的 collectAsStateWithLifecycle
方法被收集为 Compose State
对象。Category
对象具有 name
属性,该属性是表示类别名称的 String
值。
要显示类别名称,请执行以下步骤
- 在 Android Studio 中,打开启动代码的
CatalogBrowser.kt
文件,然后在CatalogBrowser
可组合函数中添加一个LazyColumn
可组合函数。 - 调用
catalogBrowserViewModel.categoryList.collectAsStateWithLifeCycle()
方法将流收集为State
对象。 - 将
categoryList
声明为在上一步骤中创建的State
对象的委托属性。 - 使用
categoryList
变量作为参数,调用items
函数。 - 使用类别名称作为参数,调用
Text
可组合函数,该参数作为 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)
}
}
}
显示每个类别的内容列表
Category
对象还有一个名为 movieList
的属性。该属性是 Movie
对象的列表,这些对象表示属于该类别的电影。
要显示每个类别的内容列表,请执行以下步骤
- 添加
LazyRow
可组合函数,然后向其传递一个 lambda 表达式。 - 在 lambda 中,使用
category
.movieList
属性值调用items
函数,然后向其传递一个 lambda。 - 在传递给
items
函数的 lambda 中,使用Movie
对象调用MovieCard
可组合函数。
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)
}
}
}
}
}
可选:调整布局
- 要设置类别之间的间距,请将
Arrangement
对象传递给LazyColumn
可组合函数,并使用verticalArrangement
参数。通过调用Arrangement#spacedBy
方法创建Arrangement
对象。 - 要设置电影卡片之间的间距,请将
Arrangement
对象传递给LazyRow
可组合函数,并使用horizontalArrangement
参数。 - 要设置列的缩进,请使用
contentPadding
参数传递一个PaddingValue
对象。
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. 实现详细信息屏幕
详细信息屏幕显示所选电影的详细信息。在 Details.kt
文件中有一个 Details
可组合函数。您需要向此函数添加代码来实现详细信息屏幕。
Details.kt
@Composable
fun Details(movie: Movie, modifier: Modifier = Modifier) {
}
显示电影标题、工作室名称和描述
一个 Movie
对象具有以下三个字符串属性作为电影的元数据
title
。电影标题。studio
。制作电影的工作室名称。description
。电影的简短概述。
要在详细信息屏幕上显示此元数据,请按照以下步骤操作
- 添加一个
Column
可组合函数,然后使用Modifier.padding
方法创建的Modifier
对象,在列周围设置 32 dp 垂直和 48 dp 水平间隙。 - 添加一个
Text
可组合函数来显示电影标题。 - 添加一个
Text
可组合函数来显示工作室名称。 - 添加一个
Text
可组合函数来显示电影描述。
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)
}
}
在 Details
可组合函数的参数中指定的 Modifier
对象将在下一任务中使用。
显示与给定 Movie
**对象** 关联的背景图片
一个 Movie
对象具有一个 backgroundImageUrl
属性,它指示由对象描述的电影的背景图片的位置。
要显示给定电影的背景图片,请按照以下步骤操作
- 添加一个
Box
可组合函数作为Column
可组合函数的包装器,并使用通过Details
可组合函数传递的modifier
对象。 - 在
Box
可组合函数中,调用modifier
对象的fillMaxSize
方法,使Box
可组合函数填充可以分配给Details
可组合函数的最大大小。 - 使用以下参数向
Box
可组合函数添加一个AsyncImage
可组合函数
- 将给定
Movie
对象的backgroundImageUrl
属性的值设置为model
参数。 - 将
null
传递给contentDescription
参数。
- 将
ContentScale.Crop
对象传递给contentScale
参数。要查看不同的ContentScale
选项,请参阅 内容比例。 - 将
Modifier.fillMaxSize
方法的返回值传递给modifier
参数。
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)
}
}
}
参考 MaterialTheme
**对象以实现一致的主题**
MaterialTheme
对象包含函数以引用当前主题值,例如 Typography
和 ColorScheme
类中的值。
要参考 MaterialTheme
对象以实现一致的主题,请按照以下步骤操作
- 将
MaterialTheme.typography.displayMedium
属性设置为电影标题的文本样式。 - 将
MaterialTheme.typography.bodySmall
属性设置为第二个Text
可组合函数的文本样式。 - 将
MaterialTheme.colorScheme.background
属性设置为使用Modifier.background
方法的Column
可组合函数的背景颜色。
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)
}
}
}
可选:调整布局
要调整 Details
可组合函数的布局,请按照以下步骤操作
- 将
Box
可组合函数设置为使用fillMaxSize
修饰符的整个可用空间。 - 使用
background
修饰符设置Box
可组合函数的背景,以使用线性渐变填充背景,该渐变是通过调用Brush.linearGradient
函数使用包含MaterialTheme.colorScheme.background
值和Color.Transparent
的Color
对象列表创建的。 - 使用
padding
修饰符,在Column
可组合函数周围设置48.dp
水平和24.dp
垂直间隙。 - 使用通过调用
Modifier.width
函数使用0.5f
值创建的width
修饰符,设置Column
可组合函数的宽度。 - 在第二个
Text
可组合函数和第三个Text
可组合函数之间添加8.dp
间距,并使用Spacer
。Spacer
可组合函数的高度由使用Modifier.height
函数创建的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. 在屏幕之间添加导航
现在您有了目录浏览器和详细信息屏幕。用户在目录浏览器屏幕上选择内容后,屏幕必须过渡到详细信息屏幕。要实现这一点,您可以使用 clickable
修饰符向 MovieCard
可组合函数添加一个 event
侦听器。按下方向键的中心按钮时,将使用与 MovieCard
可组合函数关联的电影对象作为参数,调用 CatalogBrowserViewModel#showDetails
方法。
- 打开
com.example.tvcomposeintroduction.ui.screens.CatalogBrowser
文件。 - 使用
onClick
参数向MovieCard
可组合函数传递一个 lambda 函数。 - 使用与
MovieCard
可组合函数关联的电影对象调用onMovieSelected
回调。
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. 向目录浏览器屏幕添加轮播以突出显示特色内容
轮播是一种常用的 UI 组件,它会在指定持续时间后自动更新其幻灯片。它通常用于突出显示特色内容。
要向目录浏览器屏幕添加轮播以突出显示特色内容列表中的电影,请按照以下步骤操作
- 打开
com.example.tvcomposeintroduction.ui.screens.CatalogBrowser
文件。 - 调用
item
函数向LazyColumn
可组合函数添加一个项目。 - 在传递给
item
函数的 lambda 中,将featuredMovieList
声明为委托属性,然后将State
对象设置为委托对象,该对象从catalogBrowserViewModel.featuredMovieList
属性收集。 - 在
item
函数内调用Carousel
可组合函数,然后传入以下参数
- 通过
slideCount
参数传递featuredMovieList
变量的大小。 - 一个
Modifier
对象,使用Modifier.fillMaxWidth
和Modifier.height
方法指定轮播大小。Carousel
可组合函数使用 376 dp 的高度,方法是向Modifier.height
方法传递376.dp
值。 - 一个使用整数值调用的 lambda,该整数值表示可见轮播项目的索引。
- 从
featuredMovieList
变量和给定索引值中检索Movie
对象。 - 向
Carousel
可组合函数添加一个Box
可组合函数。 - 向
Box
可组合函数添加一个Text
可组合函数以显示电影标题。
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) })
}
}
}
}
}
显示背景图片
Box
可组合函数将一个组件放在另一个组件的顶部。有关详细信息,请参阅 布局基础知识。
要显示背景图片,请按照以下步骤操作
- 在
Text
可组合函数之前,调用AsyncImage
可组合函数以加载与Movie
对象关联的背景图片。 - 更新
Text
可组合函数的位置和文本样式,以提高可见度。 - 为
AsyncImage
可组合函数设置占位符,以避免布局偏移。入门代码有一个占位符作为可绘制对象,您可以使用R.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) })
}
}
}
}
}
向详细信息屏幕添加屏幕过渡
您可以向轮播添加一个 Button
,以便用户可以通过点击按钮触发到详细信息屏幕的屏幕过渡。
要让用户在详细信息屏幕上看到可见轮播中的电影详细信息,请按照以下步骤操作
- 在
Carousel
可组合函数中的Box
可组合函数中调用Column
可组合函数 - 将
Carousel
中的Text
可组合函数移到Column
可组合函数中 - 在
Column
可组合函数中的Text
可组合函数之后调用Button
可组合函数 - 在
Button
可组合函数中调用Text
可组合函数,并使用stringResource
函数返回的值,该函数使用R.string.show_details
调用。 - 在传递给
Button
可组合函数的onClick
参数的 lambda 中,使用featuredMovie
变量调用onMovieSelected
函数
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) })
}
}
}
}
}
可选:调整布局
要调整轮播的布局,请按照以下步骤操作
- 在
Carousel
可组合函数中,使用MaterialTheme.colorScheme.background
值为backgroundColor
值赋值 - 使用
Box
可组合函数包装Column
可组合函数 - 将
Alignment.BottomStart
值传递给Box
组件的contentAlignment
参数。 - 将
fillMaxSize
修饰符传递给Box
可组合函数的修饰符参数。fillMaxSize
修饰符是使用Modifier.fillMaxSize()
函数创建的。 - 在传递给
Box
可组合函数的fillMaxSize
修饰符上调用drawBehind()
方法 - 在传递给
drawBehind
修饰符的 lambda 中,使用通过调用Brush
对象创建的brush
值,该对象是通过调用Brush.linearGradient
函数使用两个Color
对象列表创建的。该列表是通过使用backgroundColor
值和Color.Transparent
值调用listOf
函数创建的。 - 在传递给
drawBehind
修饰符的 lambda 中,使用brush
对象调用drawRect
,以在背景图像上创建 srim 层 - 使用通过调用
Modifier.padding
使用20.dp
值创建的padding
修饰符指定Column
可组合函数的填充。 - 在
Column
可组合函数中,在Text
可组合函数和Button
可组合函数之间添加一个Spacer
可组合函数,其值为20.dp
。
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. 获取解决方案代码
要下载此代码实验室的解决方案代码,请执行以下操作之一
- 单击以下按钮将其下载为 zip 文件,然后将其解压缩并在 Android Studio 中打开。
- 使用 Git 获取它
$ git clone https://github.com/android/tv-codelabs.git $ cd tv-codelabs $ git checkout solution $ cd IntroductionToComposeForTV
8. 恭喜您。
恭喜您!您学习了 Compose for TV 的基础知识
- 如何通过组合 LazyColumn 和 LazyLow 来实现显示内容列表的屏幕。
- 用于显示内容详细信息的基本屏幕实现。
- 如何在两个屏幕之间添加屏幕过渡。