Мультимедийное приложение, работающее на телевизоре, должно позволять пользователям просматривать предлагаемый контент, выбирать его и начинать воспроизведение. Просмотр контента в приложениях этого типа должен быть интуитивно понятным, визуально привлекательным и увлекательным.
Каталоги обычно состоят из нескольких разделов, в каждом из которых есть список медиаконтента. Примеры разделов в каталоге медиаконтента: плейлисты, рекомендуемый контент, рекомендуемые категории.
Используйте функции Compose for TV, чтобы реализовать пользовательский интерфейс для просмотра музыки или видео из каталога мультимедиа вашего приложения.
Создайте composable-функцию для каталога
Все, что появляется на экране, реализовано как composable-функция в Compose for TV. Начните с определения composable-функции для браузера каталога медиаконтента:
@Composable fun CatalogBrowser( featuredContentList: List<Movie>, sectionList: List<Section>, modifier: Modifier = Modifier, onItemSelected: (Movie) -> Unit = {}, ) { // ToDo: add implementation }
CatalogBrowser – это composable-функция, которая реализует браузер каталога медиаконтента. Функция принимает следующие аргументы:
- Список рекомендуемого контента.
- Список разделов.
- Объект 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) } } }
В примере composable-функция SectionRow определяет, как отображать разделы.
В следующей функции LazyRow демонстрирует, как эта горизонтальная версия LazyColumn аналогичным образом используется для определения горизонтального списка с блоком LazyListScope.() -> Unit путем вызова предоставленного DSL:
@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) } ) } } }
В composable-функции SectionRow используется компонент Text.
Текст и другие компоненты, определенные в Material Design, предлагаются в библиотеке tv-material . Вы можете изменить стиль текста, как определено в Material Design, сославшись на объект MaterialTheme.
Этот объект также предоставляется библиотекой 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. Второй можно передать как лямбда-функцию. Лямбда-выражению передается индекс отображаемого элемента. Вы можете определить, какой элемент будет показан, с помощью значения индекса:
@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 может быть элементом ленивого списка, например LazyColumn.
В следующем фрагменте кода показана composable-функция FeaturedCarousel поверх всех composable-функций SectionRow:
@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) } } }