在 TV 上运行的媒体应用需要允许用户浏览其提供的内容、选择要播放的内容,以及开始播放内容。此类应用的内容浏览体验应直观,并且视觉上要赏心悦目。
目录浏览器通常包含多个部分,每个部分都包含一个媒体内容列表。媒体目录中的版块示例包括:播放列表、精选内容、推荐类别。
使用 Compose for TV 提供的函数来实现一个用户界面,该界面可让用户浏览应用的媒体目录中包含的音乐或视频。
为目录创建可组合函数
在 Compose for TV 中,显示屏上显示的所有内容都以可组合函数的形式实现。首先,为媒体目录浏览器定义一个可组合函数:
@Composable fun CatalogBrowser( featuredContentList: List<Movie>, sectionList: List<Section>, modifier: Modifier = Modifier, onItemSelected: (Movie) -> Unit = {}, ) { // ToDo: add implementation }
CatalogBrowser 是实现媒体目录浏览器的可组合函数。该函数接受以下实参:
- 精选内容列表。
- 版块列表。
- Modifier 对象。
- 一个回调函数,用于触发屏幕过渡。
设置界面元素
Compose for TV 提供了延迟列表,该组件可用于显示大量条目(或长度未知的列表)。调用 LazyColumn 可垂直放置各个部分。LazyColumn 提供一个 LazyListScope.() -> Unit 块,该块提供一个用于定义列表条目内容的 DSL。在以下示例中,每个部分都放置在垂直列表中,各部分之间有 16 dp 的间距:
@Composable fun CatalogBrowser( featuredContentList: List<Movie>, sectionList: List<Section>, modifier: Modifier = Modifier, onItemSelected: (Movie) -> Unit = {}, ) { LazyColumn( modifier = modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(16.dp) ) { items(sectionList.size) { index -> val section = sectionList[index] SectionRow(section, onItemSelected = onItemSelected) } } }
在此示例中,SectionRow 可组合函数定义了如何显示各个部分。
在以下函数中,LazyRow 展示了如何类似地使用 LazyColumn 的这种横向版本,通过调用提供的 DSL 来定义具有 LazyListScope.() -> Unit 代码块的横向列表:
@Composable fun SectionRow( section: Section, modifier: Modifier = Modifier, onItemSelected: (Movie) -> Unit = {}, ) { Text( text = section.title, style = MaterialTheme.typography.headlineSmall, ) MovieCatalog( section.movieList, onClick = { movie -> onItemSelected(movie) }, modifier ) }
@Composable fun MovieCatalog( movies: List<Movie>, onClick: (Movie) -> Unit, modifier: Modifier = Modifier, ) { LazyRow( modifier = modifier, horizontalArrangement = Arrangement.spacedBy(8.dp) ) { items(movies.size) { index -> val movie = movies[index] MovieCard( movie = movie, onClick = { onClick(movie) } ) } } }
在 SectionRow 可组合项中,使用了 Text 组件。tv-material 库中提供了 Material Design 中定义的文本和其他组件。您可以参考 MaterialTheme 对象,更改 Material Design 中定义的文本样式。此对象也由 tv-material 库提供。Card 是 tv-material 库的一部分。MovieCard 定义了如何在目录中呈现每个电影数据,如下面的代码段所示:
@OptIn(ExperimentalMaterial3Api::class) @Composable fun MovieCard( movie: Movie, modifier: Modifier = Modifier, onClick: () -> Unit = {} ) { Card( modifier = modifier, onClick = onClick ) { AsyncImage( model = movie.thumbnailUrl, contentDescription = movie.title, ) } }
突出显示精选内容
在前面描述的示例中,所有电影的显示方式是相同的。它们具有相同的面积,在视觉上没有区别。
您可以使用 Carousel 突出显示部分内容。
轮播界面会以一组可滑动、淡入或移动到视图中的条目来显示信息。您可以使用此组件突出显示精选内容,例如新上线的电影或电视节目的新剧集。
Carousel 要求您至少指定轮播界面中的条目数量以及如何绘制每个条目。第一个可以使用 itemCount 指定。第二个可以作为 lambda 传递。系统会将所显示条目的索引号传递给 lambda。您可以使用给定的索引值来确定所显示的条目:
@OptIn(ExperimentalTvMaterial3Api::class) @Composable fun FeaturedCarousel( featuredContentList: List<Movie>, modifier: Modifier = Modifier, ) { Carousel( itemCount = featuredContentList.size, modifier = modifier, ) { index -> val content = featuredContentList[index] Box { AsyncImage( model = content.backgroundImageUrl, contentDescription = content.description, placeholder = painterResource( id = R.drawable.movie_placeholder ), contentScale = ContentScale.Crop, modifier = Modifier.fillMaxSize() ) Text(text = content.title) } } }
Carousel 可以是延迟列表的条目,例如 TvLazyColumn。以下代码段展示了位于所有 SectionRow 可组合函数顶部的 FeaturedCarousel 可组合函数:
@OptIn(ExperimentalTvMaterial3Api::class) @Composable fun CatalogBrowser( featuredContentList: List<Movie>, sectionList: List<Section>, modifier: Modifier = Modifier, onItemSelected: (Movie) -> Unit = {}, ) { LazyColumn( modifier = modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(16.dp) ) { item { FeaturedCarousel(featuredContentList) } items(sectionList) { section -> SectionRow(section, onItemSelected = onItemSelected) } } }