Медиа-приложение, работающее на телевизоре, должно позволять пользователям просматривать предложения контента, делать выбор и начинать воспроизведение контента. Опыт просмотра контента для приложений этого типа должен быть простым, интуитивно понятным, визуально приятным и привлекательным.
Браузер медиа-каталога обычно состоит из нескольких разделов, и в каждом разделе есть список медиа-контента. Примеры разделов медиакаталога: плейлисты, избранный контент, рекомендуемые категории.
![](https://developer.android.com/static/training/tv/images/compose-catalogbrowser-example.png?authuser=19&hl=ru)
Используйте функции 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
— это составная функция, реализующая браузер медиа-каталога. Функция принимает следующие аргументы:
- Список рекомендуемого контента.
- Список разделов.
- Объект модификатора.
- Функция обратного вызова, которая запускает переход экрана.
Установить элементы пользовательского интерфейса
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) { section ->
Section(section, onItemSelected = onItemSelected)
}
}
}
В этом примере функция компоновки Section
определяет, как отображать разделы. В следующей функции LazyRow
демонстрирует, как эта горизонтальная версия LazyColumn
аналогичным образом используется для определения горизонтального списка с помощью LazyListScope.() -> Unit
путем вызова предоставленного DSL:
@Composable
fun Section(
section: Section,
modifier: Modifier = Modifier,
onItemSelected: (Movie) -> Unit = {},
) {
Text(
text = section.title,
style = MaterialTheme.typography.headlineSmall,
)
LazyRow(
modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(section.movieList){ movie ->
MovieCard(
movie = movie,
onClick = { onItemSelected(movie) }
)
}
}
}
В компонуемом Section
используется компонент Text
. Текст и другие компоненты, определенные в Material Design, предлагаются в библиотеке tv-material. Вы можете изменить стиль текста, определенный в Material Design, обратившись к объекту MaterialTheme
. Этот объект также предоставляется библиотекой телевизионных материалов. Card
является частью библиотеки ТВ-материалов. MovieCard
определяет, как данные каждого фильма отображаются в каталоге, определенном в следующем фрагменте:
@Composable
fun MovieCard(
movie: Movie,
modifier: Modifier = Modifier,
onClick: () -> Unit = {}
) {
Card(modifier = modifier, onClick = onClick){
AsyncImage(
model = movie.thumbnailUrl,
contentDescription = movie.title,
)
}
}
Выделяйте рекомендуемый контент
В описанном ранее примере все фильмы отображаются одинаково. У них одинаковая площадь, визуальной разницы между ними нет. Некоторые из них вы можете выделить с помощью Carousel
.
Карусель отображает информацию в виде набора элементов, которые можно перемещать, исчезать или перемещать в поле зрения. Вы используете этот компонент, чтобы выделить избранный контент, например недавно доступные фильмы или новые эпизоды телепрограмм.
Carousel
ожидает, что вы как минимум укажете количество элементов в Carousel и способ рисования каждого элемента. Первый можно указать с помощью itemCount
. Второй можно передать как лямбду. Порядковый номер отображаемого элемента передается лямбде. Вы можете определить отображаемый элемент по заданному значению индекса:
@Composable
function 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.placeholder
),
contentScale = ContentScale.Crop,
modifier = Modifier.fillMaxSize()
)
Text(text = content.title)
}
}
}
Carousel
может быть элементом ленивого списка, например TvLazyColumn
. В следующем фрагменте показано, как можно компоновать FeaturedCarousel
поверх всех компонуемых Section
:
@Composable
fun CatalogBrowser(
featuredContentList: List<Movie>,
sectionList: List<Section>,
modifier: Modifier = Modifier,
onItemSelected: (Movie) -> Unit = {},
) {
TvLazyColumn(
modifier = modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
item {
FeaturedCarousel(featuredContentList)
}
items(sectionList) { section ->
Section(section, onItemSelected = onItemSelected)
}
}
}